//go:build generic32 // +build generic32 // SM2CurveParam implement Curve, with accelerated by Montgomery // Pure Go code, with [9]uint32 as a GFp elements package ec256 import ( "math/big" ) var ( // RInverse contains 1/R mod p - the inverse of the Montgomery constant // (2**257). c256RInverse = bigFromBase16("7ffffffd80000002fffffffe000000017ffffffe800000037ffffffc80000002") ) func init() { // fmt.Println("generic32") } // c256GetScalar endian-swaps the big-endian scalar value from in and writes it // to out. If the scalar is equal or greater than the order of the group, it's // reduced modulo that order. func c256GetScalar(out *[32]byte, in []byte) { n := new(big.Int).SetBytes(in) var scalarBytes []byte // Issue52075, if in is 33 bytes with leading 0, then panic. if n.Cmp(c256.N) >= 0 || len(in) > len(out) { n.Mod(n, c256.N) scalarBytes = n.Bytes() } else { scalarBytes = in } for i, v := range scalarBytes { out[len(scalarBytes)-(1+i)] = v } } // func (SM2CurveParam) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { // z1 := zForAffine(x1, y1) // z2 := zForAffine(x2, y2) // return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2)) // } // ScalarBaseMult overload the Curveparams's ScalarBaseMult method func (SM2CurveParam) ScalarBaseMult(scalar []byte) (x, y *big.Int) { var scalarReversed [32]byte c256GetScalar(&scalarReversed, scalar) var x1, y1, z1 [c256Limbs]uint32 c256ScalarBaseMult(&x1, &y1, &z1, &scalarReversed) return c256ToAffine(&x1, &y1, &z1) } // ScalarMult overload the Curveparams's ScalarMult method func (SM2CurveParam) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) { var scalarReversed [32]byte c256GetScalar(&scalarReversed, scalar) var px, py, x1, y1, z1 [c256Limbs]uint32 c256FromBig(&px, bigX) c256FromBig(&py, bigY) c256ScalarMult(&x1, &y1, &z1, &px, &py, &scalarReversed) x, y = c256ToAffine(&x1, &y1, &z1) return } func CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) { var scalarReversed [32]byte var px, py, x1, y1, z1, x2, y2, z2 [c256Limbs]uint32 c256FromBig(&px, bigX) c256FromBig(&py, bigY) c256GetScalar(&scalarReversed, scalar) c256ScalarMult(&x1, &y1, &z1, &px, &py, &scalarReversed) // bugfix: must set 0, for baseScalar may less than 32 bytes for i := range scalarReversed { scalarReversed[i] = 0 } c256GetScalar(&scalarReversed, baseScalar) c256ScalarBaseMult(&x2, &y2, &z2, &scalarReversed) c256PointAdd(&x1, &y1, &z1, &x1, &y1, &z1, &x2, &y2, &z2) x, y = c256ToAffine(&x1, &y1, &z1) return } // Field elements are represented as nine, unsigned 32-bit words. // // The value of an field element is: // x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228) // // That is, each limb is alternately 29 or 28-bits wide in little-endian // order. // // This means that a field element hits 2**257, rather than 2**256 as we would // like. A 28, 29, ... pattern would cause us to hit 2**256, but that causes // problems when multiplying as terms end up one bit short of a limb which // would require much bit-shifting to correct. // // Finally, the values stored in a field element are in Montgomery form. So the // value |y| is stored as (y*R) mod p, where p is the C-256 prime and R is // 2**257. const ( c256Limbs = 9 bottom29Bits = 0x1fffffff ) const bottom12Bits = 0xfff const bottom28Bits = 0xfffffff var ( // c256One is the number 1 as a field element. -- note is Montgomery form of 1, // i.e. = 1*R mod p c256One = [c256Limbs]uint32{2, 0, 0x1fffff00, 0x7ff, 0, 0, 0, 0x2000000, 0} c256Zero = [c256Limbs]uint32{0, 0, 0, 0, 0, 0, 0, 0, 0} // c256P is the prime modulus as a field element. c256P = [c256Limbs]uint32{0x1fffffff, 0xfffffff, 0x7f, 0xffffc00, 0x1fffffff, 0xfffffff, 0x1fffffff, 0xeffffff, 0xfffffff} // c2562P is the twice prime modulus as a field element. c2562P = [c256Limbs]uint32{0x1ffffffe, 0xfffffff, 0xff, 0xffff800, 0x1fffffff, 0xfffffff, 0x1fffffff, 0xdffffff, 0x1fffffff} ) // c256Precomputed contains precomputed values to aid the calculation of scalar // multiples of the base point, G. It's actually two, equal length, tables // concatenated. // // The first table contains (x,y) field element pairs for 16 multiples of the // base point, G. // // Index | Index (binary) | Value // 0 | 0000 | 0G (all zeros, omitted) // 1 | 0001 | G // 2 | 0010 | 2**64G // 3 | 0011 | 2**64G + G // 4 | 0100 | 2**128G // 5 | 0101 | 2**128G + G // 6 | 0110 | 2**128G + 2**64G // 7 | 0111 | 2**128G + 2**64G + G // 8 | 1000 | 2**192G // 9 | 1001 | 2**192G + G // 10 | 1010 | 2**192G + 2**64G // 11 | 1011 | 2**192G + 2**64G + G // 12 | 1100 | 2**192G + 2**128G // 13 | 1101 | 2**192G + 2**128G + G // 14 | 1110 | 2**192G + 2**128G + 2**64G // 15 | 1111 | 2**192G + 2**128G + 2**64G + G // // The second table follows the same style, but the terms are 2**32G, // 2**96G, 2**160G, 2**224G. // // This is ~2KB of data. var c256Precomputed = [c256Limbs * 2 * 15 * 2]uint32{ 0x830053d, 0x328990f, 0x6c04fe1, 0xc0f72e5, 0x1e19f3c, 0x666b093, 0x175a87b, 0xec38276, 0x222cf4b, 0x185a1bba, 0x354e593, 0x1295fac1, 0xf2bc469, 0x47c60fa, 0xc19b8a9, 0xf63533e, 0x903ae6b, 0xc79acba, 0x15b061a4, 0x33e020b, 0xdffb34b, 0xfcf2c8, 0x16582e08, 0x262f203, 0xfb34381, 0xa55452, 0x604f0ff, 0x41f1f90, 0xd64ced2, 0xee377bf, 0x75f05f0, 0x189467ae, 0xe2244e, 0x1e7700e8, 0x3fbc464, 0x9612d2e, 0x1341b3b8, 0xee84e23, 0x1edfa5b4, 0x14e6030, 0x19e87be9, 0x92f533c, 0x1665d96c, 0x226653e, 0xa238d3e, 0xf5c62c, 0x95bb7a, 0x1f0e5a41, 0x28789c3, 0x1f251d23, 0x8726609, 0xe918910, 0x8096848, 0xf63d028, 0x152296a1, 0x9f561a8, 0x14d376fb, 0x898788a, 0x61a95fb, 0xa59466d, 0x159a003d, 0x1ad1698, 0x93cca08, 0x1b314662, 0x706e006, 0x11ce1e30, 0x97b710, 0x172fbc0d, 0x8f50158, 0x11c7ffe7, 0xd182cce, 0xc6ad9e8, 0x12ea31b2, 0xc4e4f38, 0x175b0d96, 0xec06337, 0x75a9c12, 0xb001fdf, 0x93e82f5, 0x34607de, 0xb8035ed, 0x17f97924, 0x75cf9e6, 0xdceaedd, 0x2529924, 0x1a10c5ff, 0xb1a54dc, 0x19464d8, 0x2d1997, 0xde6a110, 0x1e276ee5, 0x95c510c, 0x1aca7c7a, 0xfe48aca, 0x121ad4d9, 0xe4132c6, 0x8239b9d, 0x40ea9cd, 0x816c7b, 0x632d7a4, 0xa679813, 0x5911fcf, 0x82b0f7c, 0x57b0ad5, 0xbef65, 0xd541365, 0x7f9921f, 0xc62e7a, 0x3f4b32d, 0x58e50e1, 0x6427aed, 0xdcdda67, 0xe8c2d3e, 0x6aa54a4, 0x18df4c35, 0x49a6a8e, 0x3cd3d0c, 0xd7adf2, 0xcbca97, 0x1bda5f2d, 0x3258579, 0x606b1e6, 0x6fc1b5b, 0x1ac27317, 0x503ca16, 0xa677435, 0x57bc73, 0x3992a42, 0xbab987b, 0xfab25eb, 0x128912a4, 0x90a1dc4, 0x1402d591, 0x9ffbcfc, 0xaa48856, 0x7a7c2dc, 0xcefd08a, 0x1b29bda6, 0xa785641, 0x16462d8c, 0x76241b7, 0x79b6c3b, 0x204ae18, 0xf41212b, 0x1f567a4d, 0xd6ce6db, 0xedf1784, 0x111df34, 0x85d7955, 0x55fc189, 0x1b7ae265, 0xf9281ac, 0xded7740, 0xf19468b, 0x83763bb, 0x8ff7234, 0x3da7df8, 0x9590ac3, 0xdc96f2a, 0x16e44896, 0x7931009, 0x99d5acc, 0x10f7b842, 0xaef5e84, 0xc0310d7, 0xdebac2c, 0x2a7b137, 0x4342344, 0x19633649, 0x3a10624, 0x4b4cb56, 0x1d809c59, 0xac007f, 0x1f0f4bcd, 0xa1ab06e, 0xc5042cf, 0x82c0c77, 0x76c7563, 0x22c30f3, 0x3bf1568, 0x7a895be, 0xfcca554, 0x12e90e4c, 0x7b4ab5f, 0x13aeb76b, 0x5887e2c, 0x1d7fe1e3, 0x908c8e3, 0x95800ee, 0xb36bd54, 0xf08905d, 0x4e73ae8, 0xf5a7e48, 0xa67cb0, 0x50e1067, 0x1b944a0a, 0xf29c83a, 0xb23cfb9, 0xbe1db1, 0x54de6e8, 0xd4707f2, 0x8ebcc2d, 0x2c77056, 0x1568ce4, 0x15fcc849, 0x4069712, 0xe2ed85f, 0x2c5ff09, 0x42a6929, 0x628e7ea, 0xbd5b355, 0xaf0bd79, 0xaa03699, 0xdb99816, 0x4379cef, 0x81d57b, 0x11237f01, 0xe2a820b, 0xfd53b95, 0x6beb5ee, 0x1aeb790c, 0xe470d53, 0x2c2cfee, 0x1c1d8d8, 0xa520fc4, 0x1518e034, 0xa584dd4, 0x29e572b, 0xd4594fc, 0x141a8f6f, 0x8dfccf3, 0x5d20ba3, 0x2eb60c3, 0x9f16eb0, 0x11cec356, 0xf039f84, 0x1b0990c1, 0xc91e526, 0x10b65bae, 0xf0616e8, 0x173fa3ff, 0xec8ccf9, 0xbe32790, 0x11da3e79, 0xe2f35c7, 0x908875c, 0xdacf7bd, 0x538c165, 0x8d1487f, 0x7c31aed, 0x21af228, 0x7e1689d, 0xdfc23ca, 0x24f15dc, 0x25ef3c4, 0x35248cd, 0x99a0f43, 0xa4b6ecc, 0xd066b3, 0x2481152, 0x37a7688, 0x15a444b6, 0xb62300c, 0x4b841b, 0xa655e79, 0xd53226d, 0xbeb348a, 0x127f3c2, 0xb989247, 0x71a277d, 0x19e9dfcb, 0xb8f92d0, 0xe2d226c, 0x390a8b0, 0x183cc462, 0x7bd8167, 0x1f32a552, 0x5e02db4, 0xa146ee9, 0x1a003957, 0x1c95f61, 0x1eeec155, 0x26f811f, 0xf9596ba, 0x3082bfb, 0x96df083, 0x3e3a289, 0x7e2d8be, 0x157a63e0, 0x99b8941, 0x1da7d345, 0xcc6cd0, 0x10beed9a, 0x48e83c0, 0x13aa2e25, 0x7cad710, 0x4029988, 0x13dfa9dd, 0xb94f884, 0x1f4adfef, 0xb88543, 0x16f5f8dc, 0xa6a67f4, 0x14e274e2, 0x5e56cf4, 0x2f24ef, 0x1e9ef967, 0xfe09bad, 0xfe079b3, 0xcc0ae9e, 0xb3edf6d, 0x3e961bc, 0x130d7831, 0x31043d6, 0xba986f9, 0x1d28055, 0x65240ca, 0x4971fa3, 0x81b17f8, 0x11ec34a5, 0x8366ddc, 0x1471809, 0xfa5f1c6, 0xc911e15, 0x8849491, 0xcf4c2e2, 0x14471b91, 0x39f75be, 0x445c21e, 0xf1585e9, 0x72cc11f, 0x4c79f0c, 0xe5522e1, 0x1874c1ee, 0x4444211, 0x7914884, 0x3d1b133, 0x25ba3c, 0x4194f65, 0x1c0457ef, 0xac4899d, 0xe1fa66c, 0x130a7918, 0x9b8d312, 0x4b1c5c8, 0x61ccac3, 0x18c8aa6f, 0xe93cb0a, 0xdccb12c, 0xde10825, 0x969737d, 0xf58c0c3, 0x7cee6a9, 0xc2c329a, 0xc7f9ed9, 0x107b3981, 0x696a40e, 0x152847ff, 0x4d88754, 0xb141f47, 0x5a16ffe, 0x3a7870a, 0x18667659, 0x3b72b03, 0xb1c9435, 0x9285394, 0xa00005a, 0x37506c, 0x2edc0bb, 0x19afe392, 0xeb39cac, 0x177ef286, 0xdf87197, 0x19f844ed, 0x31fe8, 0x15f9bfd, 0x80dbec, 0x342e96e, 0x497aced, 0xe88e909, 0x1f5fa9ba, 0x530a6ee, 0x1ef4e3f1, 0x69ffd12, 0x583006d, 0x2ecc9b1, 0x362db70, 0x18c7bdc5, 0xf4bb3c5, 0x1c90b957, 0xf067c09, 0x9768f2b, 0xf73566a, 0x1939a900, 0x198c38a, 0x202a2a1, 0x4bbf5a6, 0x4e265bc, 0x1f44b6e7, 0x185ca49, 0xa39e81b, 0x24aff5b, 0x4acc9c2, 0x638bdd3, 0xb65b2a8, 0x6def8be, 0xb94537a, 0x10b81dee, 0xe00ec55, 0x2f2cdf7, 0xc20622d, 0x2d20f36, 0xe03c8c9, 0x898ea76, 0x8e3921b, 0x8905bff, 0x1e94b6c8, 0xee7ad86, 0x154797f2, 0xa620863, 0x3fbd0d9, 0x1f3caab, 0x30c24bd, 0x19d3892f, 0x59c17a2, 0x1ab4b0ae, 0xf8714ee, 0x90c4098, 0xa9c800d, 0x1910236b, 0xea808d3, 0x9ae2f31, 0x1a15ad64, 0xa48c8d1, 0x184635a4, 0xb725ef1, 0x11921dcc, 0x3f866df, 0x16c27568, 0xbdf580a, 0xb08f55c, 0x186ee1c, 0xb1627fa, 0x34e82f6, 0x933837e, 0xf311be5, 0xfedb03b, 0x167f72cd, 0xa5469c0, 0x9c82531, 0xb92a24b, 0x14fdc8b, 0x141980d1, 0xbdc3a49, 0x7e02bb1, 0xaf4e6dd, 0x106d99e1, 0xd4616fc, 0x93c2717, 0x1c0a0507, 0xc6d5fed, 0x9a03d8b, 0xa1d22b0, 0x127853e3, 0xc4ac6b8, 0x1a048cf7, 0x9afb72c, 0x65d485d, 0x72d5998, 0xe9fa744, 0xe49e82c, 0x253cf80, 0x5f777ce, 0xa3799a5, 0x17270cbb, 0xc1d1ef0, 0xdf74977, 0x114cb859, 0xfa8e037, 0xb8f3fe5, 0xc734cc6, 0x70d3d61, 0xeadac62, 0x12093dd0, 0x9add67d, 0x87200d6, 0x175bcbb, 0xb29b49f, 0x1806b79c, 0x12fb61f, 0x170b3a10, 0x3aaf1cf, 0xa224085, 0x79d26af, 0x97759e2, 0x92e19f1, 0xb32714d, 0x1f00d9f1, 0xc728619, 0x9e6f627, 0xe745e24, 0x18ea4ace, 0xfc60a41, 0x125f5b2, 0xc3cf512, 0x39ed486, 0xf4d15fa, 0xf9167fd, 0x1c1f5dd5, 0xc21a53e, 0x1897930, 0x957a112, 0x21059a0, 0x1f9e3ddc, 0xa4dfced, 0x8427f6f, 0x726fbe7, 0x1ea658f8, 0x2fdcd4c, 0x17e9b66f, 0xb2e7c2e, 0x39923bf, 0x1bae104, 0x3973ce5, 0xc6f264c, 0x3511b84, 0x124195d7, 0x11996bd, 0x20be23d, 0xdc437c4, 0x4b4f16b, 0x11902a0, 0x6c29cc9, 0x1d5ffbe6, 0xdb0b4c7, 0x10144c14, 0x2f2b719, 0x301189, 0x2343336, 0xa0bf2ac, } var c256Precomputed8 = [c256Limbs * 2 * 256]uint32{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x19e9dfcb, 0x0b8f92d0, 0x0e2d226c, 0x0390a8b0, 0x183cc462, 0x07bd8167, 0x1f32a552, 0x05e02db4, 0x0a146ee9, 0x1a003957, 0x01c95f61, 0x1eeec155, 0x026f811f, 0x0f9596ba, 0x03082bfb, 0x096df083, 0x03e3a289, 0x07e2d8be, 0x15b061a4, 0x033e020b, 0x0dffb34b, 0x00fcf2c8, 0x16582e08, 0x0262f203, 0x0fb34381, 0x00a55452, 0x0604f0ff, 0x041f1f90, 0x0d64ced2, 0x0ee377bf, 0x075f05f0, 0x189467ae, 0x00e2244e, 0x1e7700e8, 0x03fbc464, 0x09612d2e, 0x11e57869, 0x0e17662f, 0x1ae6a0dd, 0x0438b4b8, 0x1d504420, 0x01c131f2, 0x183196d9, 0x0a7b9c5c, 0x06ad213f, 0x1ce7bb61, 0x05dcb393, 0x1e084fc6, 0x03b8feea, 0x1e7dae65, 0x085219c5, 0x1ee5bf87, 0x0683b9a9, 0x0fb426d2, 0x157a63e0, 0x099b8941, 0x1da7d345, 0x00cc6cd0, 0x10beed9a, 0x048e83c0, 0x13aa2e25, 0x07cad710, 0x04029988, 0x13dfa9dd, 0x0b94f884, 0x1f4adfef, 0x00b88543, 0x16f5f8dc, 0x0a6a67f4, 0x14e274e2, 0x05e56cf4, 0x002f24ef, 0x1e9ef967, 0x0fe09bad, 0x0fe079b3, 0x0cc0ae9e, 0x0b3edf6d, 0x03e961bc, 0x130d7831, 0x031043d6, 0x0ba986f9, 0x01d28055, 0x065240ca, 0x04971fa3, 0x081b17f8, 0x11ec34a5, 0x08366ddc, 0x01471809, 0x0fa5f1c6, 0x0c911e15, 0x0d5daec6, 0x06c10493, 0x0079be67, 0x0894cea5, 0x0799c643, 0x045b6865, 0x1737ebeb, 0x038ba924, 0x0556522c, 0x12e189f0, 0x064761c1, 0x12b03a22, 0x06c9a418, 0x001163b4, 0x01416d60, 0x10061fc8, 0x03a266c7, 0x02c80d63, 0x1569808e, 0x0d09dbd3, 0x1725dd3c, 0x0bc10628, 0x006c4642, 0x0eb20628, 0x1b6833be, 0x01b27abf, 0x0d7e96cf, 0x1838eff0, 0x0b8b7649, 0x1210aeb7, 0x016da9dd, 0x067069e4, 0x01d467d0, 0x0709fd7b, 0x0ac1473f, 0x038e858d, 0x152296a1, 0x09f561a8, 0x14d376fb, 0x0898788a, 0x061a95fb, 0x0a59466d, 0x159a003d, 0x01ad1698, 0x093cca08, 0x1b314662, 0x0706e006, 0x11ce1e30, 0x0097b710, 0x172fbc0d, 0x08f50158, 0x11c7ffe7, 0x0d182cce, 0x0c6ad9e8, 0x085c8490, 0x01cabbf4, 0x01ab7ae6, 0x0a6752f7, 0x1dd8120c, 0x04c66eb2, 0x17886d7d, 0x01579157, 0x0faaa970, 0x04d194cb, 0x0b6a6127, 0x1b7a842e, 0x0be0b3f4, 0x08999e37, 0x07fd8d56, 0x0056fa2a, 0x0923dfc1, 0x03a2eef1, 0x1e276ee5, 0x095c510c, 0x1aca7c7a, 0x0fe48aca, 0x121ad4d9, 0x0e4132c6, 0x08239b9d, 0x040ea9cd, 0x00816c7b, 0x0632d7a4, 0x0a679813, 0x05911fcf, 0x082b0f7c, 0x057b0ad5, 0x000bef65, 0x0d541365, 0x07f9921f, 0x00c62e7a, 0x0b498aca, 0x0f72c242, 0x180897a5, 0x0098569f, 0x026ce432, 0x020bed43, 0x14103d06, 0x02aaa3da, 0x09338293, 0x03dc960b, 0x0404d886, 0x129beeb2, 0x08caa293, 0x1945a51f, 0x0a6bb6fe, 0x1b3fe1e3, 0x0ed0369b, 0x0943190a, 0x0171f38d, 0x067b871e, 0x0e880eaf, 0x0ef4bb36, 0x1b17880d, 0x0ec8b62c, 0x1081fc23, 0x037e3b5e, 0x0d19f8c8, 0x10e854c0, 0x08832466, 0x04b370e0, 0x04bced12, 0x1d9cf5aa, 0x09b40a21, 0x1b8d334c, 0x08ffcf20, 0x0d1fad6c, 0x1d5baf8e, 0x01de7878, 0x1cf9455d, 0x01d57364, 0x11e91344, 0x0fb91a71, 0x0efd3234, 0x04a93fc2, 0x0fc2c6ac, 0x143cb45a, 0x024e7f88, 0x1a43d26c, 0x0a852df8, 0x1c6ebfaa, 0x053bc9a3, 0x0d30ff25, 0x0323e46c, 0x0561acee, 0x1d27a609, 0x0c2fd017, 0x055b41c6, 0x0fcc91b2, 0x0375b6f9, 0x0e6168c5, 0x056b4fff, 0x06825878, 0x03b75b9f, 0x115beafb, 0x0a15d624, 0x10ad3e07, 0x073b0b3f, 0x1d934e07, 0x05bfc456, 0x1f1f773c, 0x020ee847, 0x0dcf0f73, 0x04d70525, 0x0e4b573d, 0x1e518604, 0x05f805a1, 0x11db06a9, 0x0632d5d2, 0x095e0fc7, 0x0aaed53c, 0x0b7c7f1d, 0x136c8571, 0x07dce039, 0x0f5a7955, 0x08c0d7b8, 0x12112889, 0x00fb36be, 0x09cad65a, 0x05c3415d, 0x034e7bd1, 0x08849491, 0x0cf4c2e2, 0x14471b91, 0x039f75be, 0x0445c21e, 0x0f1585e9, 0x072cc11f, 0x04c79f0c, 0x0e5522e1, 0x1874c1ee, 0x04444211, 0x07914884, 0x03d1b133, 0x0025ba3c, 0x04194f65, 0x1c0457ef, 0x0ac4899d, 0x0e1fa66c, 0x130a7918, 0x09b8d312, 0x04b1c5c8, 0x061ccac3, 0x18c8aa6f, 0x0e93cb0a, 0x0dccb12c, 0x0de10825, 0x0969737d, 0x0f58c0c3, 0x07cee6a9, 0x0c2c329a, 0x0c7f9ed9, 0x107b3981, 0x0696a40e, 0x152847ff, 0x04d88754, 0x0b141f47, 0x1fe73ea1, 0x0b69debd, 0x1cd6d416, 0x0c32fe75, 0x0ae5951e, 0x0f6608d1, 0x0c1bfeb6, 0x0bec9ff6, 0x063ec2f9, 0x1196aeb2, 0x0ed713ce, 0x06e01a01, 0x0592e04d, 0x0f2f18e2, 0x0bb1df66, 0x018e909c, 0x01e8cc39, 0x093dc602, 0x096234b7, 0x0d8c59ac, 0x1db1fd4a, 0x044a16bd, 0x0ba682eb, 0x08e36d99, 0x1f08b5ed, 0x0361bf56, 0x0a0c1a15, 0x0191c83b, 0x0dc0102e, 0x02e5c1de, 0x0c149e51, 0x1e90f238, 0x0e334a03, 0x1c675684, 0x0abfad68, 0x0c8fda7f, 0x05a16ffe, 0x03a7870a, 0x18667659, 0x03b72b03, 0x0b1c9435, 0x09285394, 0x0a00005a, 0x0037506c, 0x02edc0bb, 0x19afe392, 0x0eb39cac, 0x177ef286, 0x0df87197, 0x19f844ed, 0x00031fe8, 0x015f9bfd, 0x0080dbec, 0x0342e96e, 0x0497aced, 0x0e88e909, 0x1f5fa9ba, 0x0530a6ee, 0x1ef4e3f1, 0x069ffd12, 0x0583006d, 0x02ecc9b1, 0x0362db70, 0x18c7bdc5, 0x0f4bb3c5, 0x1c90b957, 0x0f067c09, 0x09768f2b, 0x0f73566a, 0x1939a900, 0x0198c38a, 0x0202a2a1, 0x064b6b68, 0x07529972, 0x0f28b879, 0x0a472ee4, 0x0331ed41, 0x0bfd308f, 0x0b3e2eed, 0x0e430592, 0x0d50e110, 0x1001ba8c, 0x045c17db, 0x12f048f1, 0x064391fa, 0x1cfe2f55, 0x02296166, 0x0fb68162, 0x05110f21, 0x074cdd39, 0x0613bbff, 0x0538c6d3, 0x05b0f1a0, 0x0379d475, 0x012b4010, 0x09cade44, 0x06cccfee, 0x0656f10c, 0x0f01d6b1, 0x0b1f8e0a, 0x0a07ab3b, 0x1578ff58, 0x08d65fd9, 0x087a821e, 0x0b33dfae, 0x1af2e48e, 0x003964dd, 0x04a34d9f, 0x0f811434, 0x05385c64, 0x04c2b701, 0x09f39d85, 0x1aabc946, 0x0a729d17, 0x0ea57d83, 0x0d52d3ed, 0x0cb08ce1, 0x121291a4, 0x0d92f361, 0x1e384dc0, 0x0e4c6f5d, 0x12c2cebc, 0x0c825c7e, 0x0bdaf320, 0x0c6de19d, 0x0ef27852, 0x15de85bd, 0x0dc091fd, 0x09d6ba4d, 0x0984be1f, 0x02d7b608, 0x0c1a02a0, 0x1ccee2c5, 0x065b5233, 0x004412f2, 0x13a16af4, 0x004559f9, 0x1efc8c32, 0x0e561d9d, 0x0ea23613, 0x0bd02af9, 0x12698de3, 0x070a6e9a, 0x035f5269, 0x089fb67c, 0x02e00fa3, 0x0b75b9fe, 0x03a86d5f, 0x1bcdab02, 0x06c1fdfb, 0x177a7aea, 0x05eae942, 0x05587c32, 0x0b9bc224, 0x0b0dd56a, 0x17edda98, 0x08076c9f, 0x11b86edf, 0x067b14ce, 0x042c9fe2, 0x0f02c13f, 0x04005be5, 0x113f2879, 0x092280a7, 0x142ef0d4, 0x045a5f8e, 0x0fe4febc, 0x0d1f437f, 0x08169486, 0x025eda34, 0x037a4807, 0x1e0a14ea, 0x0dad554d, 0x13da857a, 0x01cf901a, 0x15a5b97b, 0x021e6239, 0x19561962, 0x0c5d3a16, 0x0dfe5857, 0x1ddcd62d, 0x001fa97e, 0x0d83fbff, 0x094e8607, 0x1cd36670, 0x07c4ff39, 0x01324e46, 0x0e2dc13d, 0x01b5fa1b, 0x18c18a53, 0x05d9049f, 0x1db76956, 0x0db886af, 0x07e8ac21, 0x0f9a868b, 0x0b69be5c, 0x002e1f44, 0x03e1b957, 0x144598ba, 0x0d3fbe53, 0x06bdccb4, 0x033e3ed5, 0x0407b090, 0x0d6d8c05, 0x0b8a467a, 0x0cdeb75f, 0x08470e4b, 0x115c5bfd, 0x0af69a2d, 0x0dbd08a5, 0x0361fdef, 0x07894c96, 0x0d0e93ff, 0x1548cb9b, 0x09f7240d, 0x0c1fe4c6, 0x1dc3f1be, 0x0ff1959c, 0x036ac535, 0x09ee1f5d, 0x06a57d70, 0x079e3d28, 0x0596909b, 0x04c0db6f, 0x0a033c91, 0x0c51548e, 0x08141321, 0x1e065ddc, 0x0c2b82d2, 0x1a88baff, 0x06220196, 0x09a26246, 0x04a27988, 0x0f101021, 0x0449c51c, 0x0c381f19, 0x0bb0d87b, 0x02f829b3, 0x17ec4589, 0x013dfa32, 0x1f33fbf0, 0x0e0c75fa, 0x0b7ae68e, 0x1448a62c, 0x0d169ab0, 0x04f04fcc, 0x04419488, 0x1b17d63e, 0x0590eb1d, 0x162c6984, 0x03e1662b, 0x0990176e, 0x0057bc73, 0x03992a42, 0x0bab987b, 0x0fab25eb, 0x128912a4, 0x090a1dc4, 0x1402d591, 0x09ffbcfc, 0x0aa48856, 0x07a7c2dc, 0x0cefd08a, 0x1b29bda6, 0x0a785641, 0x16462d8c, 0x076241b7, 0x079b6c3b, 0x0204ae18, 0x0f41212b, 0x11a93be0, 0x03c13fb5, 0x03f43d23, 0x0aa87a80, 0x09879e92, 0x028a11c8, 0x1bfdbe48, 0x0628587b, 0x0772a0f4, 0x12f58fa9, 0x008608f6, 0x04db9801, 0x07ec89dc, 0x09dcff0e, 0x08935861, 0x0333cab0, 0x09d5c767, 0x058dfc89, 0x10f7b842, 0x0aef5e84, 0x0c0310d7, 0x0debac2c, 0x02a7b137, 0x04342344, 0x19633649, 0x03a10624, 0x04b4cb56, 0x1d809c59, 0x00ac007f, 0x1f0f4bcd, 0x0a1ab06e, 0x0c5042cf, 0x082c0c77, 0x076c7563, 0x022c30f3, 0x03bf1568, 0x0575a508, 0x0d90e7ff, 0x1fe1aadc, 0x09879c2a, 0x00f43535, 0x04123057, 0x01e1587e, 0x02e9a291, 0x07c0dc06, 0x0db64406, 0x07a67b2e, 0x066bd577, 0x0af4a697, 0x1bd82c6d, 0x0566d973, 0x15ca37c3, 0x0f8c4c06, 0x05b56740, 0x1ee3271e, 0x05fec91c, 0x0010db95, 0x078221e6, 0x09c830bb, 0x0c735720, 0x1e972fe9, 0x02e48283, 0x0f008112, 0x0423f988, 0x020f9f24, 0x1456119d, 0x064b434e, 0x0802fad0, 0x006e4eed, 0x173eebf6, 0x061d2a12, 0x0f73b1af, 0x165f18f8, 0x05fea09d, 0x07bafd96, 0x00840fbb, 0x100be02a, 0x0fc0b030, 0x0219f693, 0x05c851b4, 0x08e58aad, 0x18e2f266, 0x05cb20a7, 0x1df8a0b8, 0x023be06e, 0x1d1bc46a, 0x0f7e22c2, 0x1570d805, 0x0c58c2c5, 0x06825626, 0x08e38b8f, 0x0e4232d5, 0x069a9cac, 0x02637dae, 0x08bf4864, 0x0d5bbfb4, 0x0155ed69, 0x06bdce66, 0x0134f4c5, 0x1cb5bac7, 0x09e8ce21, 0x1005af9e, 0x005a00bb, 0x04bba3f1, 0x0d77d877, 0x0677910b, 0x0cb5fa2d, 0x0d0445b2, 0x1d6e8e6b, 0x07c6070b, 0x01680952, 0x0a4b15d8, 0x1248b317, 0x0713fffe, 0x1a3cbe08, 0x061bc114, 0x0d01a1a5, 0x02a57d09, 0x04783785, 0x14080386, 0x0b85366c, 0x0ac0f32d, 0x0b24fdca, 0x1a16ce42, 0x09276140, 0x0673423c, 0x00be1db1, 0x054de6e8, 0x0d4707f2, 0x08ebcc2d, 0x02c77056, 0x01568ce4, 0x15fcc849, 0x04069712, 0x0e2ed85f, 0x02c5ff09, 0x042a6929, 0x0628e7ea, 0x0bd5b355, 0x0af0bd79, 0x0aa03699, 0x0db99816, 0x04379cef, 0x0081d57b, 0x1f7caab4, 0x0e95107b, 0x13851c2b, 0x07dbf3bd, 0x1f93cdbb, 0x0520c62d, 0x09afac0c, 0x0701fbc2, 0x084a329d, 0x132c8e97, 0x09a386a2, 0x1ed313c8, 0x0f8d8268, 0x1c0618c6, 0x077201f0, 0x09b80514, 0x0754717c, 0x081bf7b5, 0x11cec356, 0x0f039f84, 0x1b0990c1, 0x0c91e526, 0x10b65bae, 0x0f0616e8, 0x173fa3ff, 0x0ec8ccf9, 0x0be32790, 0x11da3e79, 0x0e2f35c7, 0x0908875c, 0x0dacf7bd, 0x0538c165, 0x08d1487f, 0x07c31aed, 0x021af228, 0x07e1689d, 0x1c9f66f1, 0x0d9a1145, 0x08e94cfb, 0x02d7390e, 0x05852b5f, 0x0904be86, 0x05a4c8b7, 0x0db55f0d, 0x0307f68f, 0x119bd1d5, 0x02e62492, 0x10d00353, 0x0933ed5f, 0x1a74611a, 0x0a2415c6, 0x127ef157, 0x007ac0a0, 0x0a2320ae, 0x176c056a, 0x0ff545bc, 0x0413abb3, 0x0288a5ec, 0x1a952b37, 0x06612d74, 0x14ba6bbf, 0x001e8afd, 0x0b75c935, 0x023b1000, 0x0e4695bf, 0x0ec25d07, 0x02a5b7ea, 0x033880d6, 0x09bb4adc, 0x15359913, 0x0c3b0c0b, 0x051767cb, 0x1a67616d, 0x00e6f835, 0x173cc2e9, 0x0966e0ae, 0x15fa5da2, 0x09f0df3f, 0x1398bafa, 0x0f632793, 0x0206b6c4, 0x01e9af6e, 0x045279e4, 0x1329ba5c, 0x0b3a9947, 0x0c9ebcce, 0x067cd7f2, 0x0741ef12, 0x00013498, 0x0faaf3b7, 0x09802718, 0x0c1d0146, 0x0403c5d9, 0x0e2620d6, 0x1079878d, 0x01994dfc, 0x1fbb7a73, 0x09e3a80c, 0x010298bc, 0x1cb17b2a, 0x004e4238, 0x1a7231ee, 0x017437e4, 0x0f896693, 0x0db2ee3f, 0x14228b22, 0x0102d31b, 0x0ee548d6, 0x131a346b, 0x0cb1957d, 0x1ae5edf7, 0x00bcca96, 0x1260bafd, 0x0fdb76c0, 0x0d484e1e, 0x010afafe, 0x066e0d69, 0x1afc55a8, 0x0cedf390, 0x0b3e0af2, 0x083bc12d, 0x045f04db, 0x0ff6497b, 0x17d9fd3a, 0x0bbf9496, 0x0dff64dd, 0x1fd2133f, 0x02696e9a, 0x1a925c06, 0x0af8ae03, 0x0fcaa7b4, 0x0c28b6b8, 0x0c61c07c, 0x04e8bc99, 0x0f3098ac, 0x1d768882, 0x0afee1c6, 0x19ad454f, 0x0b7a9fd2, 0x0ae3fdfc, 0x01b882e9, 0x0f694c2e, 0x0721c084, 0x0ddf4b0f, 0x04b9498d, 0x0161f6d5, 0x096eae64, 0x04d611a6, 0x1c6d8dcb, 0x09631c0c, 0x04be65d5, 0x0e411bbe, 0x040c998d, 0x18e7951c, 0x0438c3e1, 0x05e7b0db, 0x061f8e41, 0x1acd0775, 0x0f651967, 0x0721d240, 0x021b30e6, 0x044e1818, 0x05b4aefb, 0x0f7375f8, 0x1a1fa7fb, 0x0eac256e, 0x1ecb78c8, 0x0d002a7e, 0x0401a9cd, 0x085b8e67, 0x05035409, 0x0c4e88d9, 0x077b3ac0, 0x1c08b6fe, 0x010c39c5, 0x12b02733, 0x06f77e98, 0x14e0c56c, 0x0bc32cf1, 0x0225749f, 0x03be44b7, 0x01d9e52a, 0x0fdd9bb3, 0x08574fff, 0x1788899d, 0x0978a7e6, 0x0cf000fd, 0x04bbe028, 0x05b1090f, 0x095e4dff, 0x061e2f6a, 0x0ff192f2, 0x0a5b14fb, 0x0067abf4, 0x03506b29, 0x0ed19029, 0x0f78b9ae, 0x076594dd, 0x11fe5394, 0x09a8e835, 0x0a65f926, 0x027bb3ea, 0x1f90da4e, 0x0fe50115, 0x071d608c, 0x0923948f, 0x0292eab4, 0x019b5a76, 0x02048234, 0x1f5d429f, 0x0d100876, 0x0054a977, 0x04a9a10f, 0x11f833e0, 0x02bdc276, 0x07d369aa, 0x1c7d9cca, 0x0d87e43f, 0x111f19ec, 0x003f6972, 0x0af21625, 0x08ccaf22, 0x00c33bc2, 0x0903636f, 0x0b49ccf3, 0x06b7de68, 0x0577167f, 0x1a98acff, 0x04d443f4, 0x101a7eca, 0x0a6a0b90, 0x06bb366d, 0x03c14649, 0x072c1733, 0x1fb3fc0b, 0x0c15d09b, 0x04454a74, 0x0934fdbb, 0x174f5fea, 0x06e57ef3, 0x0f5d5cdd, 0x0d609334, 0x0ac90e48, 0x1ba1c7be, 0x0aeea190, 0x12c184d4, 0x03bf9ccd, 0x13c3edd2, 0x0c711dbd, 0x1b7fea59, 0x0465a397, 0x08086b1e, 0x0b405849, 0x0021a6f1, 0x05c3eaec, 0x0c86b99a, 0x05ac6c7e, 0x03e18d1b, 0x00137bac, 0x03518c74, 0x01c633f3, 0x1f7d2b2c, 0x065c88f3, 0x17f362ae, 0x00913162, 0x065a66a2, 0x06cdde1d, 0x1d2d2476, 0x0f9453df, 0x034d9842, 0x03f19097, 0x07acf316, 0x07a3108f, 0x0960f772, 0x1c6352d3, 0x04390dcf, 0x1505b09a, 0x03b3a072, 0x080ba5b4, 0x18fd248e, 0x0230c542, 0x1531dd70, 0x0c98be74, 0x1bc7614e, 0x03be43c7, 0x1765a0e8, 0x0aa0a6ea, 0x0fba0b90, 0x1999dd96, 0x04d2c9d0, 0x10596790, 0x017cfe83, 0x179e4488, 0x064e204f, 0x0d744bd0, 0x03effca6, 0x05d91506, 0x06db12f2, 0x00e16747, 0x0549a6b6, 0x0c9b5d80, 0x02f5c88a, 0x04569902, 0x01f7d3cb, 0x0a1ee544, 0x08a2ff4a, 0x05be97e7, 0x0efcd0bc, 0x02333b6c, 0x010f3165, 0x1d8279a6, 0x075f748f, 0x122fd2f2, 0x0a5df515, 0x00311f88, 0x1a4fc9fe, 0x098a9308, 0x1e52828f, 0x0a925ab6, 0x13498bb7, 0x0d0994ee, 0x10eb0d5c, 0x098f22f7, 0x02309d1a, 0x00526dba, 0x0a15b850, 0x1f129e58, 0x09ae2c2f, 0x13cf996d, 0x017cb1d9, 0x14c72176, 0x0b0412eb, 0x0389c257, 0x1527d551, 0x0c049647, 0x0767440f, 0x0d21471b, 0x149ff9d5, 0x0fe84130, 0x1c41fe9c, 0x02311a60, 0x021904a0, 0x09aedd1b, 0x09ad306f, 0x02a0be5c, 0x043ee9c9, 0x0a299bf3, 0x0fa77fed, 0x14741ab3, 0x012c7232, 0x090a4a52, 0x190c0352, 0x0de48cfc, 0x17337334, 0x03c5bac5, 0x0fffe278, 0x0258a2f6, 0x158a8f30, 0x07dfa269, 0x0b7d8e13, 0x02c27f2e, 0x0fe957c6, 0x1694cbd4, 0x04eeff9a, 0x1ce15c37, 0x0e6a829f, 0x0b195c02, 0x0f4f13e9, 0x069349b7, 0x106aa78e, 0x06b7cf84, 0x1dff2583, 0x0872af03, 0x1c72720f, 0x0c4a122e, 0x0a39c729, 0x098014ff, 0x0c4b6677, 0x132f6e8a, 0x04ead414, 0x0b76980f, 0x02362c05, 0x0df8d59f, 0x056a15c6, 0x14f80435, 0x07ce6097, 0x01fd2ccf, 0x09d5c78c, 0x0112a0a4, 0x0808a78e, 0x0707ac52, 0x0abee986, 0x00c570cb, 0x070feb1e, 0x0592ba1c, 0x03c9642a, 0x19a63671, 0x057f4dee, 0x0b43e67d, 0x0318e0a3, 0x138d2832, 0x03a0fc9f, 0x0d17dd68, 0x060a739b, 0x0731a2b3, 0x0df86084, 0x01caf074, 0x0ec3fd94, 0x0711fc31, 0x10bad872, 0x02cbf71a, 0x1bd8df8b, 0x086b1386, 0x0a484ab0, 0x04bbf5a6, 0x04e265bc, 0x1f44b6e7, 0x0185ca49, 0x0a39e81b, 0x024aff5b, 0x04acc9c2, 0x0638bdd3, 0x0b65b2a8, 0x06def8be, 0x0b94537a, 0x10b81dee, 0x0e00ec55, 0x02f2cdf7, 0x0c20622d, 0x02d20f36, 0x0e03c8c9, 0x0898ea76, 0x08e3921b, 0x08905bff, 0x1e94b6c8, 0x0ee7ad86, 0x154797f2, 0x0a620863, 0x03fbd0d9, 0x01f3caab, 0x030c24bd, 0x19d3892f, 0x059c17a2, 0x1ab4b0ae, 0x0f8714ee, 0x090c4098, 0x0a9c800d, 0x1910236b, 0x0ea808d3, 0x09ae2f31, 0x087c796d, 0x039e3648, 0x0125285a, 0x0d1c6f0c, 0x1705792c, 0x09455e18, 0x04e5244b, 0x055d2f18, 0x00285749, 0x088c41aa, 0x0348db92, 0x0c8074b8, 0x0c829d23, 0x1a37733f, 0x0ffe8798, 0x0f486ae6, 0x00c9e36e, 0x00882aee, 0x1aac3778, 0x0acb8240, 0x1ced327d, 0x017e8ba9, 0x181bbe3e, 0x0d5fcebe, 0x15765dd1, 0x021adc74, 0x0427fc6e, 0x01a9e424, 0x0d3d8d55, 0x065a38a6, 0x00540cc3, 0x08c533a6, 0x0b553ca9, 0x14c44b83, 0x0f1f2046, 0x03732b57, 0x1a15ad64, 0x0a48c8d1, 0x184635a4, 0x0b725ef1, 0x11921dcc, 0x03f866df, 0x16c27568, 0x0bdf580a, 0x0b08f55c, 0x0186ee1c, 0x0b1627fa, 0x034e82f6, 0x0933837e, 0x0f311be5, 0x0fedb03b, 0x167f72cd, 0x0a5469c0, 0x09c82531, 0x0b92a24b, 0x014fdc8b, 0x141980d1, 0x0bdc3a49, 0x07e02bb1, 0x0af4e6dd, 0x106d99e1, 0x0d4616fc, 0x093c2717, 0x1c0a0507, 0x0c6d5fed, 0x09a03d8b, 0x0a1d22b0, 0x127853e3, 0x0c4ac6b8, 0x1a048cf7, 0x09afb72c, 0x065d485d, 0x06b68d54, 0x003d9842, 0x19d5a242, 0x08638f10, 0x129ad9af, 0x06c8f16e, 0x12a4e90a, 0x0f222355, 0x0fddf76e, 0x08bb0ec0, 0x0b99023c, 0x03938867, 0x0c32a1e7, 0x0760507b, 0x04076fcd, 0x0e2abec6, 0x065b9dac, 0x09293191, 0x1a10e282, 0x03fb6793, 0x1b7ff539, 0x04996fde, 0x04e9f439, 0x06892e9b, 0x02c86ffc, 0x052f5aec, 0x06327bd4, 0x018fc28a, 0x0e5a7411, 0x0493bf0a, 0x07a14d8c, 0x088f4f3e, 0x0e8721c4, 0x0e6828ef, 0x05b4219e, 0x0645e69d, 0x1eecc415, 0x0f4a643f, 0x033033c5, 0x0c899cc1, 0x1055edc1, 0x0fbabaf3, 0x162dddea, 0x0e72c3c7, 0x0cc21bda, 0x0f780644, 0x08f85ddd, 0x1cf88784, 0x0632782d, 0x16cc326f, 0x07c2174f, 0x1e0cbd0f, 0x0415f297, 0x05c2a1d3, 0x1f61f5d8, 0x0f209eed, 0x0ec9775b, 0x05438c53, 0x0b93a8a7, 0x0c3b412a, 0x04e56dc7, 0x0db692c6, 0x08ca178e, 0x10308524, 0x0cc758d5, 0x1aceab22, 0x0a1fcf64, 0x05db8a96, 0x01b8247c, 0x1e52d1d8, 0x0e36fa9c, 0x0db44e1d, 0x0e6a3709, 0x02e1d912, 0x1a475b66, 0x0e91ce6d, 0x090cae4c, 0x034159f2, 0x06db2bf8, 0x05a831c5, 0x01b63da5, 0x0e536bc9, 0x0d4e136e, 0x102493b6, 0x0a63d36a, 0x0a838638, 0x034fd202, 0x1e48354e, 0x08616404, 0x0830fabf, 0x1a28812e, 0x098b046a, 0x088b1ae8, 0x037fc126, 0x1cd762e5, 0x066e33d1, 0x0027406d, 0x052422b2, 0x0bd9b275, 0x02e2dbce, 0x0b4b1d86, 0x1641b5f4, 0x08f03ac6, 0x1d090c3d, 0x031728fc, 0x060f1a52, 0x09dcfc2a, 0x07082481, 0x1c678301, 0x09fbc3e1, 0x1e3e3837, 0x0dcb1f0a, 0x0f2f3aa7, 0x00e0dc44, 0x0ee8e902, 0x0993eeaf, 0x0b0f01c0, 0x0a8bf671, 0x0941a11e, 0x1542313b, 0x0d10deae, 0x0346913d, 0x09cf3f30, 0x1dd76036, 0x08cc01c4, 0x0a760aaf, 0x175551fe, 0x0dd38190, 0x1c51befd, 0x068bda2d, 0x1c54ec8b, 0x01e9aa1b, 0x047e6068, 0x016586c9, 0x046222ad, 0x1440b357, 0x0628fa0d, 0x134fe9d1, 0x0bf74917, 0x04a63129, 0x0e28c35e, 0x1efcd338, 0x0c2cfcac, 0x088c973b, 0x031fa4d3, 0x05439469, 0x10b8edf3, 0x0cbeefe0, 0x0ddbb0e6, 0x0e057f3e, 0x09d7e239, 0x0d998b49, 0x09d07ce1, 0x1b08ab32, 0x091847f7, 0x12a4ac48, 0x059b9f02, 0x162ed8d1, 0x043bda4c, 0x191a65ae, 0x010244f2, 0x09ca7e6e, 0x135e8dff, 0x036584f4, 0x18bce8e7, 0x08077d7c, 0x1dc884b6, 0x0509384c, 0x1addfc06, 0x0dbe7209, 0x0a216693, 0x00853876, 0x0131a138, 0x1abf7196, 0x05c41787, 0x07ff23cd, 0x0379e299, 0x13d0288b, 0x0632a587, 0x02cb241a, 0x072d5998, 0x0e9fa744, 0x0e49e82c, 0x0253cf80, 0x05f777ce, 0x0a3799a5, 0x17270cbb, 0x0c1d1ef0, 0x0df74977, 0x114cb859, 0x0fa8e037, 0x0b8f3fe5, 0x0c734cc6, 0x070d3d61, 0x0eadac62, 0x12093dd0, 0x09add67d, 0x087200d6, 0x0175bcbb, 0x0b29b49f, 0x1806b79c, 0x012fb61f, 0x170b3a10, 0x03aaf1cf, 0x0a224085, 0x079d26af, 0x097759e2, 0x092e19f1, 0x0b32714d, 0x1f00d9f1, 0x0c728619, 0x09e6f627, 0x0e745e24, 0x18ea4ace, 0x0fc60a41, 0x0125f5b2, 0x02c096eb, 0x0da778c6, 0x003316ca, 0x032320f4, 0x084230f2, 0x082a9606, 0x1baf1fce, 0x06e6c2df, 0x069e54d7, 0x081b4ff0, 0x02bafb85, 0x16225a48, 0x0ace7fa6, 0x12874fea, 0x0d628717, 0x01e83c75, 0x0fd0e568, 0x06b842dc, 0x09e83e2e, 0x0114bc7a, 0x030c21ae, 0x0f20267d, 0x0f2e493c, 0x08143d70, 0x097e97ac, 0x0f710392, 0x030e45d3, 0x18477e66, 0x08d7a37b, 0x1c1056ff, 0x063aed00, 0x16a38eae, 0x0fb61e6f, 0x158e2db9, 0x0d1d947c, 0x0355c9ed, 0x0c3cf512, 0x039ed486, 0x0f4d15fa, 0x0f9167fd, 0x1c1f5dd5, 0x0c21a53e, 0x01897930, 0x0957a112, 0x021059a0, 0x1f9e3ddc, 0x0a4dfced, 0x08427f6f, 0x0726fbe7, 0x1ea658f8, 0x02fdcd4c, 0x17e9b66f, 0x0b2e7c2e, 0x039923bf, 0x01bae104, 0x03973ce5, 0x0c6f264c, 0x03511b84, 0x124195d7, 0x011996bd, 0x020be23d, 0x0dc437c4, 0x04b4f16b, 0x011902a0, 0x06c29cc9, 0x1d5ffbe6, 0x0db0b4c7, 0x10144c14, 0x02f2b719, 0x00301189, 0x02343336, 0x0a0bf2ac, 0x16a20198, 0x04d731e5, 0x14313f12, 0x030539ce, 0x031c27bc, 0x0cc04483, 0x140f60a4, 0x098c9cb5, 0x0172f0da, 0x0730bd21, 0x0a427c02, 0x09b8822c, 0x08600a44, 0x19486de3, 0x0e058753, 0x0368a4bf, 0x05b65bb4, 0x02e1e3eb, 0x1184c047, 0x0c10eda4, 0x1927c812, 0x03e28979, 0x15ced911, 0x039da245, 0x16872f88, 0x004c05f2, 0x09faa7cd, 0x00261bab, 0x0dc9993a, 0x0be0f9bc, 0x079e6326, 0x1fb74ddb, 0x09fa2a99, 0x06134b6a, 0x0e440d74, 0x0ec4dbef, 0x08ee635e, 0x03b2df7c, 0x1a1f3735, 0x08352bdc, 0x17d23b38, 0x07ddda85, 0x0ff57f99, 0x0a387200, 0x09acbd71, 0x1cdb2713, 0x01702fb0, 0x099878fd, 0x0e923648, 0x06475fa4, 0x0fcd3934, 0x192a138b, 0x0789e0dc, 0x07b786ee, 0x0c0e455e, 0x02627ed1, 0x1f0d0f2d, 0x0c081145, 0x0b0e1e45, 0x06723b13, 0x131babd3, 0x0a582fe5, 0x036975fe, 0x08b28124, 0x05a3e23b, 0x029bf54f, 0x05122bec, 0x01110a5a, 0x01796969, 0x007e97b8, 0x01d81fc0, 0x00741b0a, 0x1b018eae, 0x0242d5cb, 0x06b1a686, 0x01ff69cb, 0x1e7a69a1, 0x035a4b9f, 0x1c1742b5, 0x0494f3e7, 0x0a8b76a5, 0x006ee8b4, 0x02226342, 0x1a47cca1, 0x094ff2e4, 0x1d56dac6, 0x009c8502, 0x08f336a6, 0x06ed8ed3, 0x0c07c73a, 0x00ace43e, 0x0480cd28, 0x07f6a3a5, 0x0247266b, 0x1854fc5d, 0x094b7f6f, 0x0b323719, 0x0f6fc3db, 0x07ae0c95, 0x0612c4bd, 0x054ea36a, 0x0c180fc4, 0x0011204b, 0x130a8135, 0x00461f94, 0x0efa7d40, 0x07787ae0, 0x0ef4364a, 0x1818f809, 0x0eb380b9, 0x01cc9c26, 0x03e568f8, 0x16371180, 0x0cbca16d, 0x0b71377e, 0x039a5fcf, 0x079b8fea, 0x1512c7a4, 0x0bc65344, 0x155dd742, 0x05eaf13d, 0x0c3a17d0, 0x0ecb639e, 0x0ddf924f, 0x099097f2, 0x02e2114d, 0x0c56ed37, 0x066bef19, 0x19d9f370, 0x07f631d3, 0x05888c1a, 0x0d2f3f9c, 0x17830f51, 0x0d3028ab, 0x0fe628dc, 0x13fb4b43, 0x0b4292fe, 0x02297610, 0x0aa0654f, 0x1b888806, 0x0a8ea8b7, 0x05c10461, 0x04e77842, 0x09fb1442, 0x04eea8ca, 0x0529ea28, 0x1e46b020, 0x09cb282e, 0x101ecb5e, 0x0d5dbf80, 0x173abf7d, 0x0f7093c3, 0x0066e13e, 0x08817911, 0x090f2627, 0x0bda8659, 0x0cc6d6b1, 0x1b320cfe, 0x02006cea, 0x131bd824, 0x04dc0baa, 0x0c73791f, 0x13249868, 0x0f93624a, 0x11428f85, 0x05feb970, 0x0f7ec23c, 0x015d1fe7, 0x04e0527e, 0x07ea13f3, 0x00c20a11, 0x026e49d5, 0x09ebe1f5, 0x1c8b23c1, 0x01050f92, 0x0efde7f8, 0x06129caf, 0x0e253cd9, 0x0c77d820, 0x05d80bfa, 0x14c70c11, 0x02f2cf4d, 0x168ac04c, 0x021cc33d, 0x1fb1d90a, 0x0ddf6e57, 0x05dfc62f, 0x057308d2, 0x0a17e7c5, 0x0e62b5ff, 0x005e86ea, 0x1bf9e4c1, 0x052a9579, 0x08ccb2d0, 0x087248d4, 0x0e8c427d, 0x0488c9a6, 0x0e023284, 0x181e64a1, 0x03eca283, 0x08aef966, 0x064b6c7d, 0x059e5a18, 0x0e7da300, 0x1e726e72, 0x08870c8b, 0x0df75008, 0x07a3c8a8, 0x05e077b1, 0x0e51afbe, 0x019eae97, 0x120dcca0, 0x06b8f0ea, 0x118de43f, 0x0cc8b164, 0x0cce298d, 0x017f080c, 0x0b13cf6d, 0x168e16c1, 0x079b0057, 0x132b2468, 0x0c620e72, 0x03c70151, 0x04b48349, 0x015c446f, 0x03e1b204, 0x0dc67971, 0x1ea87cef, 0x02de8a0c, 0x1be789d6, 0x0335bc19, 0x14f81a76, 0x06602da8, 0x08560d41, 0x15d0d3bb, 0x0d184fa6, 0x14becb7d, 0x0affb626, 0x0c00d1df, 0x009682ee, 0x0b3c5d8e, 0x08f57ef3, 0x09527eb5, 0x1565938f, 0x07dfd230, 0x10ea273a, 0x0842bd74, 0x0beaa321, 0x05ccdef2, 0x05e5a48c, 0x05385705, 0x02abb940, 0x1290d7e9, 0x06b288e1, 0x1d922dff, 0x030bc510, 0x0c7ba05d, 0x083770cd, 0x01746fbc, 0x0e46e602, 0x0d7d4c1e, 0x0ec5c4fe, 0x0b79c281, 0x1a2505ee, 0x0f5629cf, 0x1ec83b2c, 0x0809121e, 0x16fd2575, 0x0bfef2f8, 0x0f6da95e, 0x0639aeba, 0x064eb131, 0x0e3be27a, 0x0a79ae58, 0x0ef9c8fb, 0x000c8e67, 0x08390514, 0x021bffcb, 0x06e370ce, 0x105a1f01, 0x09c13f46, 0x1bd72df6, 0x00d5e92e, 0x098e121c, 0x0cf36e69, 0x0f78868c, 0x09e7ec15, 0x05dbb933, 0x1e887464, 0x0b47bff2, 0x07a6c0cd, 0x0de326c7, 0x122ec811, 0x02958aa7, 0x173dad23, 0x0dfaee6f, 0x075a7bf9, 0x1700b7c5, 0x082fced4, 0x1b5ad6b7, 0x01767b58, 0x1b9b1e03, 0x0a180166, 0x0b8fd67f, 0x0846d88d, 0x0ef9dba1, 0x0c53a267, 0x089b3bb5, 0x12712924, 0x04dca968, 0x0c177cf8, 0x0b7dc20a, 0x0754edff, 0x081a57d7, 0x08aae66e, 0x196eab13, 0x07a38e55, 0x065eef04, 0x0ded86fb, 0x12cde5bd, 0x0f26b8f0, 0x031907f7, 0x03aee0bb, 0x001c6994, 0x12fd1f9d, 0x09b2251b, 0x02fa92fe, 0x090e3172, 0x1b32d2ea, 0x0f8de9e7, 0x10d71cf4, 0x0d3cf830, 0x02534b22, 0x08a7eef5, 0x08733ba2, 0x0bd44db0, 0x08e42804, 0x11d9100c, 0x01b092c9, 0x1205fe7c, 0x054ea075, 0x0fffb9b3, 0x09130d68, 0x0e991af9, 0x100ec143, 0x0e8a4112, 0x1491861c, 0x0cae79f7, 0x17b64f09, 0x0d2d21e9, 0x0433c270, 0x14c56856, 0x00282bca, 0x08bc91bc, 0x030cb427, 0x0271bc69, 0x03d11e05, 0x02850e4c, 0x0b99227b, 0x0bd824e6, 0x18847df8, 0x08788ad3, 0x1f9bf099, 0x053a8dbf, 0x17271163, 0x03363fa0, 0x1e5e846c, 0x0619188b, 0x0ea71b65, 0x0da67c44, 0x04e5fa85, 0x0e570896, 0x09171dd8, 0x1d4918ce, 0x0c8715f7, 0x00f19f90, 0x0df45c14, 0x08cb6b65, 0x1060914f, 0x080bad98, 0x0fb31161, 0x06bb82f1, 0x048c76f8, 0x03fd0bc4, 0x15bc8bd8, 0x0d02fc80, 0x0b348838, 0x1855b2c4, 0x05b00eb4, 0x0f4c871b, 0x00ec74e6, 0x1cbf8718, 0x053517e3, 0x1e155fd8, 0x0dc1e3c8, 0x0d9831e5, 0x0b16ba86, 0x067d9b89, 0x0b773b56, 0x08c4c70f, 0x05c303df, 0x0362fd52, 0x1b61469b, 0x0485ad68, 0x0485b084, 0x16cab85e, 0x00ba08d7, 0x17c978d5, 0x04886e6f, 0x1c07913c, 0x05ecc1ad, 0x1ce756ff, 0x00dc6030, 0x0d9486fc, 0x00242f99, 0x020de762, 0x1cec6e5d, 0x046306a9, 0x142364d2, 0x077f3d9c, 0x17ef797c, 0x0d006d27, 0x02af9c20, 0x0cf81013, 0x05929160, 0x061c6e82, 0x0a96e41d, 0x129395e7, 0x0e99fa2a, 0x0462b37e, 0x0a6e5096, 0x0b5b1e8a, 0x0ed514ac, 0x04023c96, 0x1282d58f, 0x074ce3c6, 0x158e0648, 0x069bf1b5, 0x00b92fa9, 0x0d5139c8, 0x0d9e3664, 0x008ce05b, 0x06b1dd21, 0x0ac15186, 0x0b365529, 0x015b2fdb, 0x0ad74906, 0x0b1b19e2, 0x0e163008, 0x03f92ae8, 0x123c26ba, 0x06e2d45f, 0x190edaf9, 0x0fc44a3f, 0x1914aa5b, 0x0577edce, 0x1e0cdb68, 0x041a4236, 0x09b2e3a0, 0x01fe028e, 0x074c3fc5, 0x0808cc19, 0x0282e436, 0x16b38d8a, 0x0c09b044, 0x1fb399aa, 0x04180463, 0x0d3f5f46, 0x06433ec6, 0x0a41222c, 0x04763633, 0x0986da54, 0x03738383, 0x07692085, 0x02127d73, 0x051efd01, 0x01e76034, 0x09daacea, 0x00d3c702, 0x0ebd84d5, 0x02bc7e89, 0x15eb3f2b, 0x01a8db97, 0x0feb95d3, 0x08622921, 0x074d4e00, 0x1fa60035, 0x09537c03, 0x087fa999, 0x0c39b8ab, 0x0dfb1496, 0x05603b5d, 0x18d8f866, 0x016f77ca, 0x0f5b3b76, 0x0661adef, 0x03248816, 0x023a2c0a, 0x0f8857d6, 0x14ae81da, 0x06f2f138, 0x064ea4e7, 0x0663625e, 0x047cc233, 0x0517218a, 0x062064ee, 0x1d0be9f6, 0x0bf4bfbc, 0x05702b1e, 0x0b295afb, 0x178d0cc2, 0x0d6d63c7, 0x0f8c9a57, 0x036a6cf1, 0x0c53abe3, 0x0da6090d, 0x0454ff28, 0x160c1a30, 0x02705bd9, 0x13d3c6c2, 0x067eb8d8, 0x0a153a99, 0x0c8d45b0, 0x0bc2176f, 0x0f9f984f, 0x04e96fe5, 0x1ecbdacd, 0x052f8e63, 0x1758f50e, 0x09289017, 0x004dff37, 0x04bd6d1f, 0x0cb2a85b, 0x133abbb1, 0x06c55cf6, 0x01439b80, 0x0a273141, 0x09194f0f, 0x0ce3ef0c, 0x0f03750c, 0x1c3549df, 0x00eeb8be, 0x18bc249b, 0x084ede9f, 0x0d52c40f, 0x043faf8c, 0x07b7867b, 0x0268420f, 0x08240a08, 0x1f3f7632, 0x0be613d7, 0x02f1ae6a, 0x0599fa60, 0x12552407, 0x0662f1e2, 0x07e609c8, 0x0200c18b, 0x0e77ae97, 0x0d35c7ba, 0x01334cc8, 0x110baee3, 0x020a1cc0, 0x0b66295b, 0x021eee37, 0x0b095bf8, 0x08a33ba2, 0x053ee7a9, 0x056b7ca6, 0x0ece3d3e, 0x1f83443f, 0x03df75ea, 0x1080aab4, 0x0158042f, 0x1fc95fd9, 0x037356dd, 0x070721e0, 0x0ab97666, 0x0d7c70d1, 0x044142d7, 0x01d734f5, 0x11eba3c1, 0x06b77246, 0x0e91fa71, 0x08ea6258, 0x0b9d208f, 0x08d2cad0, 0x0e98cc51, 0x1ab64470, 0x07e4cb20, 0x1f18cd17, 0x0168876b, 0x07d1fbe8, 0x04b58b6e, 0x059df556, 0x1fd6a0e2, 0x0f323281, 0x0a0cf7ff, 0x06816faa, 0x04dfe8b6, 0x03b44e3e, 0x0e3adbe6, 0x0affefa7, 0x0a62c8e2, 0x13257330, 0x0d104efc, 0x19571e01, 0x026591d8, 0x0e092d3e, 0x0cdd6e4f, 0x046a1cb9, 0x06e92a91, 0x045cf53b, 0x078da2f8, 0x06015053, 0x16fbcb1e, 0x0adb0063, 0x07b2f61e, 0x0b840181, 0x02c8faef, 0x08ac880a, 0x0252b397, 0x00475266, 0x058df49f, 0x0421e2ea, 0x0e644c90, 0x09002c5c, 0x0c6f025e, 0x0abcac4f, 0x0535e2c4, 0x035591c6, 0x0c517a4e, 0x0ee9c0e2, 0x0d8926de, 0x0f6e4b7c, 0x13812f68, 0x05a2e9b1, 0x1a12ef1e, 0x0388f72f, 0x0e38236b, 0x127fbb31, 0x09af35cd, 0x18d80ea6, 0x0b1f416c, 0x05a69287, 0x02452a1e, 0x1765903b, 0x070bd618, 0x0b329a47, 0x0c8c1be1, 0x0463c268, 0x15e7932a, 0x0bae837e, 0x09ec845b, 0x05d61027, 0x0345385e, 0x01e6f52b, 0x0cd1d28d, 0x1402b916, 0x019e649c, 0x1c7b2a65, 0x087bad1a, 0x01fc6b18, 0x02672acd, 0x1dfc7ebb, 0x0865eef5, 0x036472f3, 0x0e1d1952, 0x09222c76, 0x103512bd, 0x0ecbb525, 0x1e419c0d, 0x0b29a51b, 0x1b67174e, 0x034de662, 0x0b427b8e, 0x1e4bd2f6, 0x0bf23640, 0x055b35bc, 0x00d05b7f, 0x15676eba, 0x0c1e1736, 0x009d229d, 0x08ee4237, 0x005b3b02, 0x0e3e404b, 0x041551b7, 0x0d71870b, 0x0f3784ed, 0x08c3c498, 0x0e961347, 0x00d8cec2, 0x0d3f69d9, 0x0002ec04, 0x07fda23f, 0x01740c3a, 0x11c6c98a, 0x056d0c71, 0x0f0da4ee, 0x0f5b441e, 0x1d6e5bc2, 0x05a06bdb, 0x0a64b637, 0x125a3a81, 0x04e0e7ab, 0x06c63b0b, 0x020bd563, 0x16394349, 0x01621cd7, 0x1273cd03, 0x046bef12, 0x06b0ad2c, 0x02e2a2c9, 0x00a0b91b, 0x0dabfa51, 0x00be41e9, 0x1880c326, 0x07dea536, 0x04d20376, 0x061e0709, 0x04fbff10, 0x1f700422, 0x032471c1, 0x1f78eda0, 0x0915ab14, 0x041c23e1, 0x0d5ad34d, 0x0124a98a, 0x091d1193, 0x04801c84, 0x07b793b1, 0x0924289d, 0x008df62f, 0x00a537a5, 0x088292be, 0x0059a825, 0x00e56408, 0x0617fba7, 0x0eb58a8a, 0x14ddef75, 0x0ff049d3, 0x17b13417, 0x0bceb390, 0x0155de63, 0x0dc21433, 0x1bfa854c, 0x06d4f197, 0x0272cf86, 0x030c0bd4, 0x072faa2c, 0x16939cdb, 0x017b7af0, 0x127c6ef7, 0x0d0bab83, 0x03fd4efc, 0x05fbb8b0, 0x029c4b2e, 0x05f3d5eb, 0x07b1a6a3, 0x1c13dbef, 0x007ca967, 0x056f9622, 0x0f159ac6, 0x0fcb3ce6, 0x023e02a6, 0x073273fd, 0x1074c8a0, 0x01c45533, 0x10208703, 0x0b569f80, 0x09b00b6c, 0x0a55407c, 0x0232f5be, 0x00cbf2d8, 0x0ccfa7d4, 0x0ecbee14, 0x03afe9c7, 0x1c5912c8, 0x02b54400, 0x157693d9, 0x0703f210, 0x14b08062, 0x0da04c9a, 0x0053472e, 0x09f1bfcc, 0x00145c3f, 0x1cb8ce3f, 0x0b4de034, 0x06e15c37, 0x0ad94a9f, 0x056500ba, 0x09d26f51, 0x06da088e, 0x15a7464f, 0x08a05bcb, 0x1395df72, 0x06a0809e, 0x1ddef778, 0x03d23d64, 0x0fde1762, 0x03fe1e7c, 0x04d7f883, 0x0b6d1ca7, 0x01a811fb, 0x11d018d6, 0x0c25b32f, 0x1b210f7f, 0x03589744, 0x1bf6c71c, 0x0f36f757, 0x03773a40, 0x02db5775, 0x0361a12a, 0x11927651, 0x09b6177e, 0x0b379b52, 0x0d544929, 0x1580a6c8, 0x0d2c9302, 0x00c95322, 0x18955df5, 0x02f8ca3a, 0x0e1e084e, 0x0ff43cea, 0x0b9cc7f6, 0x052f5ea7, 0x0a53ac68, 0x07bf8473, 0x0d93ad4f, 0x180faca3, 0x0733e774, 0x0def63d7, 0x0bfef34a, 0x16a3f836, 0x06950fd3, 0x18c7b0f3, 0x03f58854, 0x005c3420, 0x1bbe35f4, 0x0908f38d, 0x08008b2f, 0x083fb8b9, 0x0e8953f0, 0x00e8d09a, 0x0c3ae4c7, 0x084de44b, 0x064fe9d7, 0x1c55fd1b, 0x0eb69275, 0x1c426781, 0x0521c117, 0x0397bcdd, 0x06f28170, 0x1e6a45e7, 0x06fc4aa6, 0x04784e78, 0x08c24a33, 0x044f3bd2, 0x0e08b63c, 0x03a62ebe, 0x1105ed9e, 0x053211a6, 0x10ab7407, 0x07519507, 0x0c3c5f59, 0x1f179166, 0x05ae18a6, 0x079e64b9, 0x00f69aeb, 0x1b86cd99, 0x0398b377, 0x0869bdfb, 0x0a8ad728, 0x0096f481, 0x153aa920, 0x0c54b280, 0x16aa05f8, 0x06b42178, 0x0952271d, 0x0dd9dffd, 0x1d549d9d, 0x0d5a05f6, 0x013ea570, 0x14bb908f, 0x067f67d9, 0x035271cd, 0x0919c7bc, 0x0494c06d, 0x0140c3a8, 0x1eee45cc, 0x041e9984, 0x0c30d4bd, 0x0539164c, 0x0ca98e78, 0x0b0edc84, 0x004bcc98, 0x182cbbdd, 0x0c42e5dd, 0x0c6e221d, 0x072b1b61, 0x085ec657, 0x03f768ed, 0x0c868695, 0x1f3c5d2b, 0x0c2f2fd2, 0x061d4887, 0x0f9ec832, 0x0683bad4, 0x0337d5e5, 0x02994d4c, 0x0be112eb, 0x0cd4b1e6, 0x17772714, 0x016aa8b8, 0x1d90e8d3, 0x0588f94f, 0x0fbcd390, 0x0c3c6033, 0x0e647828, 0x0fdeb44d, 0x07d111e7, 0x09a0e189, 0x0e39463f, 0x138de48b, 0x04895223, 0x0672b092, 0x02d965f6, 0x07f0e360, 0x1b3a9c00, 0x0cd1bdd1, 0x1505e053, 0x0e5c0e6e, 0x1c75160f, 0x09dd4f40, 0x01a4c606, 0x0cdd8eda, 0x0550dba4, 0x0f3666d3, 0x04d9e4d9, 0x0b6a94e2, 0x09d7fa75, 0x164549a3, 0x0c95cac2, 0x0422d986, 0x0fa52158, 0x0fd04187, 0x05f050c7, 0x0169cd98, 0x0a0bbc65, 0x0f29b174, 0x1bd72de4, 0x07643ee7, 0x1fd7fe77, 0x07c5e1b2, 0x0906f20c, 0x1a00b414, 0x06c72560, 0x08d5fe10, 0x0bb9e620, 0x1aed35f7, 0x0c723956, 0x19c8ec9d, 0x05f3e7ad, 0x0a075c1c, 0x06aecd93, 0x065c5782, 0x1d7d68ee, 0x0f9d7aac, 0x1f0ab87e, 0x006eeba5, 0x1e68dce2, 0x0396cd87, 0x0299daa9, 0x1dba2ba8, 0x07aab718, 0x1854d244, 0x0ab44e73, 0x0f00a335, 0x013daa28, 0x1d6e7e91, 0x08adbbc3, 0x03b35fca, 0x18f2cc77, 0x0d7c1a29, 0x188bbf94, 0x06886f74, 0x042c8fdf, 0x02723147, 0x1ae1509e, 0x0e676882, 0x05f57b2f, 0x1f84f72d, 0x0f8fd5cb, 0x005246f0, 0x07a2a492, 0x072acd9a, 0x07c68940, 0x170f7ecc, 0x0889592c, 0x0d059c67, 0x0df7b138, 0x0ef3dc50, 0x03d77589, 0x03fd18df, 0x04e9c5e4, 0x06a5afc4, 0x04e1c449, 0x09b5de9b, 0x01011f48, 0x01144cbb, 0x04274716, 0x0349fba1, 0x031578dc, 0x1a98da11, 0x01a68e77, 0x11d7b481, 0x0f89fa5f, 0x005502fc, 0x0fd845e3, 0x02fa0a97, 0x0b8c80cd, 0x01b0f91c, 0x01d570b2, 0x07f404af, 0x1e6cc419, 0x02ad7551, 0x0f9d2d0b, 0x1936b859, 0x0b148959, 0x1f1dcd79, 0x0793afa9, 0x1f2ec067, 0x01bce976, 0x133b00e2, 0x0d9eba8d, 0x0d2fab58, 0x1c392693, 0x00038137, 0x1f11ac5c, 0x025a08f0, 0x0ec84f4e, 0x09e5848b, 0x007ba0f8, 0x05d1674f, 0x067257a5, 0x17b598a5, 0x00107c90, 0x11c04731, 0x07810f00, 0x002999aa, 0x0e0d6f50, 0x03c54c05, 0x0ce9420d, 0x08dd82b3, 0x1254961a, 0x0a3fe5a3, 0x04e75429, 0x05553510, 0x05616a47, 0x015ed0e8, 0x036b2eac, 0x02026b1c, 0x023de87b, 0x1656373c, 0x02841440, 0x007ac02c, 0x01203e26, 0x030030c1, 0x01282eae, 0x0dab6978, 0x04aad2c2, 0x059b1cc8, 0x05eefda1, 0x01dbdca3, 0x000fa331, 0x05f24ab8, 0x02789931, 0x0e34024e, 0x1e68557e, 0x0d4a5358, 0x078608a6, 0x0cdf996f, 0x0bc7b1b0, 0x00b4a035, 0x0a143666, 0x1af186cc, 0x0232988f, 0x0512e5a0, 0x05106df4, 0x097231de, 0x19773cc5, 0x0c341736, 0x0246650b, 0x0d0459bd, 0x14525f80, 0x0fb15709, 0x0fa283ea, 0x08271a53, 0x05125054, 0x06e9cf56, 0x0c62d134, 0x056c804d, 0x013d8539, 0x1357ec77, 0x0d48947f, 0x08c72446, 0x006b2ab5, 0x0b4712f9, 0x1cbe94fb, 0x068cf34b, 0x1de59943, 0x04d60cda, 0x18b5a63b, 0x06dc4094, 0x028a1a07, 0x013b0553, 0x0615f4b0, 0x03e25cca, 0x03615407, 0x1d57bdc2, 0x09f7d501, 0x124c20b7, 0x02d2065f, 0x110d1477, 0x0842ca1d, 0x0921d561, 0x0202eb0e, 0x09e4a73a, 0x16b7d8ee, 0x0dc2e1c5, 0x1385bf7d, 0x00c2125f, 0x0b289169, 0x07145614, 0x0d7f1261, 0x036f308d, 0x03a16b86, 0x0a8b0a0a, 0x0ce36f16, 0x1ef2b663, 0x029e96ac, 0x04963c00, 0x0dd6f1d4, 0x0f1ab0c4, 0x0200424a, 0x0b33d149, 0x18c041f3, 0x0da33f70, 0x058df1bd, 0x056983d5, 0x162e245a, 0x09340f11, 0x07f69156, 0x1d6f4030, 0x07e0556f, 0x0ba4c7cf, 0x01c77a0d, 0x048b639b, 0x07d1a1b2, 0x1cd75c7f, 0x052c8cdd, 0x0b503171, 0x1d64460c, 0x0f23cb2e, 0x0d295619, 0x07348b70, 0x0bcd2eda, 0x0a2921ee, 0x13528799, 0x0d3f8331, 0x03e2962b, 0x0df5d2fb, 0x00d729a8, 0x0f2edec7, 0x012bd41f, 0x012dc210, 0x0c50892e, 0x15609605, 0x02afb5fd, 0x05639a95, 0x1597ec0f, 0x0bfb357d, 0x1a1a715a, 0x02a89ec9, 0x1496a64e, 0x0d6f408f, 0x0753259b, 0x04439fc3, 0x0d39a664, 0x0fdf3e37, 0x05eefffb, 0x1bcdb42d, 0x0c38febe, 0x16e3f0ef, 0x0c5a3509, 0x1e8d352b, 0x04d15f89, 0x0c9e13c6, 0x023d892a, 0x07bd013e, 0x02f7cc86, 0x008229c8, 0x068d1888, 0x0a28f1cd, 0x1540d724, 0x0fed2bac, 0x0a05d018, 0x14f57847, 0x01d33d39, 0x01d38c33, 0x08bc8371, 0x033c7fdd, 0x08ce0eef, 0x14a76fd0, 0x0f3c5f76, 0x0d7ef0ee, 0x068af61c, 0x030e41b4, 0x183446b7, 0x078e73f3, 0x1d72f3b3, 0x0414b688, 0x0a412e9b, 0x0c376aed, 0x0c0213a5, 0x13a9bcbb, 0x0785b0aa, 0x198e0866, 0x03b5318c, 0x17d6994d, 0x0eef8d2e, 0x0a2e9408, 0x0dcf6821, 0x0762978c, 0x07a3e0ea, 0x05f97af6, 0x1d9181e6, 0x01c5b977, 0x0e1d0aef, 0x0a08ab98, 0x18e72fda, 0x0d12a801, 0x087feda9, 0x13076723, 0x0c39625d, 0x1b4ae120, 0x02e34eee, 0x1da57379, 0x06c90bde, 0x1e681f3f, 0x068f2339, 0x0fca591e, 0x0bcd888b, 0x0009c07f, 0x09a108b7, 0x003d3148, 0x18409252, 0x0ecb2798, 0x16840dd6, 0x0a04b603, 0x06ede279, 0x1d6006d4, 0x040f1909, 0x008579b0, 0x0efdc043, 0x057b0f15, 0x05d343bb, 0x0ecddc09, 0x0d5cc717, 0x07e4a60c, 0x05ad13f9, 0x04559611, 0x04c3f786, 0x042b6c36, 0x0cd87435, 0x0912fa91, 0x1749c171, 0x07269a05, 0x004b74a6, 0x06364ae9, 0x0ce3f8c2, 0x1f82bc8f, 0x03d1bcdc, 0x08a935a1, 0x08d0557e, 0x0099b750, 0x0390ce41, 0x0c051c44, 0x1c5a0f03, 0x01285aa3, 0x1b6425a1, 0x0d9c7de2, 0x172d3830, 0x0d6197ea, 0x0aaba899, 0x0ea689d9, 0x0e2f1326, 0x16f7695a, 0x0ec4c921, 0x0ee5a53b, 0x0ff3996c, 0x059bd569, 0x0814dd9e, 0x11a3488d, 0x00edf3d7, 0x040f1f98, 0x05de1892, 0x057650bc, 0x0090e565, 0x00f2b574, 0x1fc120c7, 0x08d5f547, 0x1d8bbbdc, 0x0d10d4c9, 0x01bae45b, 0x0f3804fa, 0x00d37815, 0x0d24e486, 0x0c016270, 0x16a9d7d7, 0x0c752e02, 0x09ae6112, 0x08ccf79e, 0x0b563f84, 0x1161d13e, 0x0f6a304d, 0x1f4287b6, 0x0fe45ffa, 0x1d5ced8e, 0x0c24e17e, 0x02caf7a1, 0x060e27b0, 0x062c07c7, 0x000720a9, 0x0abe8f48, 0x157dc687, 0x054f22a8, 0x0ea952a3, 0x02ae0b4d, 0x0631d916, 0x037a6af6, 0x0d2a396b, 0x0425cd3a, 0x0566757d, 0x0e9dcc1f, 0x0497c35d, 0x0dd5667e, 0x0f662bbd, 0x15ccbe27, 0x01d0e707, 0x0a58b70d, 0x17280784, 0x085c96d0, 0x06cc2667, 0x008e23a0, 0x1d6d21cb, 0x0adb60ce, 0x11b32800, 0x0432af99, 0x0e1d14fe, 0x0c96c66b, 0x0e88175b, 0x0ccf0789, 0x0d986e39, 0x0647982a, 0x04e6759b, 0x066eac21, 0x063a9532, 0x018b1304, 0x0c7240f1, 0x0a663ea4, 0x12125936, 0x09044c33, 0x0684a5f7, 0x0ff54228, 0x0b29f65e, 0x0c2a1b75, 0x07a38bca, 0x0977465b, 0x0cc32cc4, 0x1526ac7a, 0x0afe0b45, 0x18c5b0cc, 0x0c7127a6, 0x0e90ef3c, 0x00f1f1bf, 0x0c9950a7, 0x196205e6, 0x0e7ffa3d, 0x1237cf0a, 0x04fab619, 0x0420e523, 0x074e32a4, 0x0159dd85, 0x0af24589, 0x06f44a32, 0x0cd289e7, 0x0a16723b, 0x0e05c8b2, 0x0a083cf0, 0x1f32a8c5, 0x01bfc685, 0x0a95adfa, 0x06a445d2, 0x0074548f, 0x174b61cd, 0x09e95980, 0x11e166ad, 0x09dd8e0a, 0x0995d6eb, 0x0ec5f025, 0x14844232, 0x0cab1008, 0x05634179, 0x116fb355, 0x0bfa3f69, 0x0ecc1c53, 0x09b1d8f8, 0x119f5188, 0x0a0f4022, 0x0575e017, 0x0aff0ed3, 0x0479f54b, 0x014cb3ef, 0x072dc050, 0x0e8565be, 0x00c03d3d, 0x054b3ca2, 0x0de3e8e3, 0x1d26d744, 0x0d475079, 0x0ba2f352, 0x0dcf4baa, 0x0f4417fb, 0x076bb0b4, 0x082e5249, 0x1c16223f, 0x0ce60085, 0x0ef7a027, 0x0363298c, 0x0d33d7cc, 0x0428d878, 0x08584155, 0x0d124aa8, 0x0d18eba1, 0x09498ef9, 0x0324cb24, 0x076ac3c1, 0x087bee47, 0x07bd6139, 0x17fd3174, 0x0eba4e29, 0x108495a3, 0x06e6be26, 0x0205f7bd, 0x05dcf0ab, 0x1017a191, 0x0e49d563, 0x0f0587be, 0x0df41722, 0x059e8e86, 0x1fda819f, 0x0d76cc5e, 0x1ba00daa, 0x007a3f42, 0x1ccea890, 0x0ef8177b, 0x0956acad, 0x0a7fa931, 0x08029802, 0x0a883336, 0x0739a9c0, 0x0eb86073, 0x052f62ea, 0x04198f37, 0x0f7f8b51, 0x03d4ed9e, 0x0513904f, 0x0f823def, 0x18a49a24, 0x011448bd, 0x0b3329a9, 0x0425a1c8, 0x1fe2fe0e, 0x0ced9bb6, 0x0f5e971b, 0x0f90b0dc, 0x0f618a64, 0x19580860, 0x0399aae5, 0x12ef4a77, 0x005ceb70, 0x154470c9, 0x09716e83, 0x07c18a49, 0x0b39385c, 0x0c1e4157, 0x068aa0b4, 0x0c661740, 0x0663e756, 0x07ecacfe, 0x17267efd, 0x077446f4, 0x0dd97ded, 0x04f7fc89, 0x0fc16ad5, 0x1dde2e40, 0x0a3fe19a, 0x1970f5a4, 0x0a0b237d, 0x0ffa401a, 0x0a37fcdd, 0x0c226a47, 0x050192aa, 0x05285284, 0x0b35d3f4, 0x05ecd3b1, 0x0366588f, 0x02845aba, 0x01a40a29, 0x0b3b8035, 0x01f098d3, 0x1c818eb1, 0x00da1cf3, 0x1a639745, 0x0310e44c, 0x0acd89b6, 0x0ecb95b1, 0x1cec3e21, 0x0bd318c2, 0x0b6eefce, 0x03ba953c, 0x002e2c05, 0x0d040316, 0x04b502ee, 0x1c2ca700, 0x0f288fba, 0x0f3265c0, 0x0210f6a0, 0x03465886, 0x02246fdf, 0x019c1be2, 0x17d47772, 0x04c96a29, 0x0a0bae26, 0x04aaed30, 0x1b725a7f, 0x0f0c5d6e, 0x0914818b, 0x0935c562, 0x07db23f2, 0x0f3af657, 0x07e7b8be, 0x1c6fb30d, 0x08f88e73, 0x0450c8df, 0x07c2c093, 0x0258d57d, 0x04b221e5, 0x09c55397, 0x1474dcc8, 0x0a401131, 0x0c882a04, 0x0c6ab3b6, 0x1ff7891b, 0x0326366e, 0x04cb5d98, 0x01cae883, 0x0913e6e2, 0x199abace, 0x0db9315d, 0x00277e5c, 0x003cd32f, 0x0a50aa64, 0x0025e92b, 0x03c5e2d4, 0x180d8de2, 0x046a0021, 0x063635dc, 0x002fce8b, 0x17dd419d, 0x069a9654, 0x1d40a609, 0x012f6c47, 0x0a0c9d9c, 0x07f8f896, 0x04b5c756, 0x1ab7695c, 0x093702e4, 0x00f28507, 0x0c191f36, 0x002beb0c, 0x0d7c40d5, 0x04c1ac1f, 0x19bd7328, 0x02988af5, 0x1a12cec4, 0x0b312596, 0x1d2ed170, 0x07c29181, 0x09ba06e4, 0x07222a4f, 0x0e0fccd0, 0x0d4b95c5, 0x06c70d53, 0x0659e320, 0x096447a9, 0x00c41cb2, 0x098f6869, 0x08b7e67d, 0x07002c30, 0x095d3e43, 0x064b3e83, 0x0081c55a, 0x112b55a6, 0x0858dfe4, 0x1aae8f58, 0x057b0ab9, 0x1de744c4, 0x07166508, 0x0c6bd549, 0x10c2717f, 0x0d80ee13, 0x0d8fc16c, 0x01d30a7f, 0x0198e1e4, 0x0c1f54aa, 0x0f7329df, 0x01d80c52, 0x0853b9d8, 0x0ea473f7, 0x0d7f3962, 0x1c2efd81, 0x054510ce, 0x1851b159, 0x0ec9317f, 0x03ddff45, 0x0aed9b3e, 0x006893d6, 0x0484b28d, 0x07aae4d4, 0x0ebe242e, 0x0225da9e, 0x102e5071, 0x04905293, 0x1986c6e9, 0x06d83222, 0x0f10d2fd, 0x08a4d9f5, 0x029579ed, 0x0f37f90d, 0x02358128, 0x16ebd653, 0x06499096, 0x0f51363d, 0x0338ecb1, 0x05cddfa6, 0x047b73f6, 0x057685db, 0x19e8d674, 0x0beecd35, 0x0e98596d, 0x0897afb1, 0x0d9e3f00, 0x0bd593ec, 0x03310695, 0x125211e8, 0x06fd154f, 0x1772b0a2, 0x0e706477, 0x0c0d3127, 0x0744a26c, 0x098bbb2a, 0x0044aeba, 0x0c5bc384, 0x07bca8f0, 0x05659252, 0x165f9ed1, 0x065623d6, 0x06cc2eaa, 0x0bcd669c, 0x0dae6c55, 0x0b006052, 0x08e93909, 0x0af0fcec, 0x0647d612, 0x1515ecbe, 0x0c9a9951, 0x00552e91, 0x06f711a2, 0x08c1d46a, 0x0a9b00d6, 0x0ae03a32, 0x008212c9, 0x0d41aa68, 0x1f759832, 0x044a5c53, 0x005901d3, 0x0064a84f, 0x1fe930fd, 0x0ddb7ca9, 0x02842b43, 0x053efc1c, 0x06c6d08b, 0x12deb6eb, 0x0cb66f75, 0x1fa69691, 0x0df185e1, 0x1e7d3cf6, 0x00610f04, 0x01397346, 0x17830f44, 0x0d45ba56, 0x007369c9, 0x08cf3890, 0x0cc4ec87, 0x026c8ed0, 0x051b4e18, 0x016335bc, 0x0512b7e3, 0x1d7c0000, 0x01c1bb8c, 0x1f98d52e, 0x0bf68a8d, 0x1b5b61ba, 0x03da8fa9, 0x0a293f2c, 0x06317cbb, 0x0f77fe53, 0x1d52c8b5, 0x07bfb89a, 0x0c76eb7c, 0x03fb5de9, 0x17cf4f75, 0x06def89c, 0x14dafd45, 0x07bf2c88, 0x0f085ef9, 0x0ed85d0e, 0x09c73359, 0x010aa85e, 0x0d1e715c, 0x0fc60602, 0x0926ef2b, 0x14149438, 0x0debc291, 0x06844c33, 0x138af1e4, 0x01d0cca1, 0x1ea283ea, 0x041adcde, 0x016a0fd4, 0x00c2a9d5, 0x1c4f8d00, 0x0ab87078, 0x0f6b5d8f, 0x0dde042d, 0x0bd208c3, 0x052e663d, 0x00a480ca, 0x189f0f43, 0x01b0c2c5, 0x1f225d2c, 0x0fb0102b, 0x0de1c834, 0x050decc4, 0x03a0b7e0, 0x0a77c573, 0x0d266ded, 0x18d4644a, 0x05c3796b, 0x1c168f95, 0x0ac2b17e, 0x09fafefa, 0x1402aa19, 0x0f21ac04, 0x0708f999, 0x08c6b660, 0x00030180, 0x0386080a, 0x18e9ffe7, 0x0a58c881, 0x0c6d31b1, 0x027a1178, 0x0cfd0960, 0x05388973, 0x0fbb8377, 0x05213399, 0x0d1c3789, 0x023f1707, 0x0cef79ff, 0x04971c1a, 0x1096bf02, 0x04873059, 0x03d47fdb, 0x052051ee, 0x057b37c8, 0x00f9c284, 0x0250a06f, 0x05758bbc, 0x0f371400, 0x180bc4b9, 0x037ff6e5, 0x125ecb6f, 0x0ab95fbf, 0x1ce9dac2, 0x01bea65e, 0x07b982ca, 0x011cde64, 0x033f3cde, 0x0a995a8c, 0x0ce75d57, 0x06b25fc6, 0x04005834, 0x0bdf5c61, 0x07ce8531, 0x049b6355, 0x04327e7e, 0x0b002311, 0x1a04b8a5, 0x0ecc00a1, 0x190d25d0, 0x07175119, 0x016215af, 0x0cd02e0c, 0x1ee5c535, 0x0e005ea8, 0x0885bfd5, 0x156b2f3d, 0x0e621d1e, 0x00251661, 0x0129a8c2, 0x026d70f2, 0x06698ef7, 0x12b69862, 0x01beed19, 0x0f7cf361, 0x1ef7aa53, 0x04c8d757, 0x09973693, 0x03b9a69d, 0x0be9a921, 0x046fdca8, 0x04220f12, 0x0d4f0e15, 0x0874a078, 0x19a6b1f7, 0x0d06705b, 0x0b78cdcc, 0x0c1fdb01, 0x0da216a6, 0x02403bd9, 0x0fc930f0, 0x04e48c79, 0x07d002fa, 0x12be8d8f, 0x0245bc82, 0x0c7ef038, 0x089e7cb4, 0x0fae74e8, 0x00f58a32, 0x115e0f22, 0x0bd0a602, 0x0e32192a, 0x1d96b499, 0x0417f0b7, 0x02e50ef4, 0x0c182d69, 0x0fb72360, 0x00e2cd85, 0x15f6866b, 0x026251f1, 0x0a010db7, 0x1093cca7, 0x01d37086, 0x1f87581b, 0x0555f678, 0x183346d9, 0x0d662611, 0x03780830, 0x082df955, 0x0189209c, 0x03f5a987, 0x0147c4f8, 0x10f6665d, 0x000554e4, 0x001655db, 0x0a0f2463, 0x151b695d, 0x0ba9a379, 0x0da4a3c6, 0x027165c3, 0x0c484bd9, 0x097ae7b6, 0x065aa228, 0x196bf437, 0x0d3d415c, 0x177829f5, 0x037af661, 0x0bfeefc6, 0x15373b1b, 0x09bb90da, 0x07599363, 0x09fd3c0e, 0x1f07d53c, 0x0a4b5038, 0x054d629f, 0x0a96a908, 0x0a15933e, 0x15bd1112, 0x0def3089, 0x1f758f5f, 0x03ef3c02, 0x05f26054, 0x0d2ce019, 0x038a4484, 0x0e429c44, 0x03996ca2, 0x00da28c3, 0x01c28206, 0x08c75ccf, 0x0abae662, 0x06bd4500, 0x00a5d02c, 0x0b110dd0, 0x0327c45b, 0x0846a1e8, 0x0a68b911, 0x078df873, 0x0ae7d3fe, 0x0883eadd, 0x115228c2, 0x09951a30, 0x152e80e1, 0x00d8739c, 0x03ab8500, 0x0077f633, 0x0af4c82c, 0x14add41c, 0x0dfdd4d8, 0x1cbc2be9, 0x0f87edbc, 0x107849ff, 0x0a767b82, 0x03f2eb40, 0x0d1ab2e0, 0x0e6fa9dd, 0x0bd79576, 0x0ec79be2, 0x02b2add4, 0x00a05ff0, 0x190f4215, 0x0a9b28c8, 0x0d0c4c44, 0x128d2951, 0x039b9c19, 0x0e532e37, 0x0a18f78f, 0x0cb8156a, 0x09c15dcd, 0x1a6139af, 0x0cae12b5, 0x04efacfe, 0x16c1c902, 0x06f9b615, 0x070d78bb, 0x03221fc2, 0x167f59c3, 0x0f4cdc1e, 0x1f819c49, 0x0ee7718c, 0x002c5071, 0x0c83c192, 0x020e76ec, 0x0094352f, 0x0ef669d2, 0x0e049c71, 0x0be355da, 0x0e8fc702, 0x022558a9, 0x0e9dc2aa, 0x18859ae4, 0x0735eb1d, 0x1304f833, 0x09976b49, 0x17354abb, 0x08c60487, 0x0445d761, 0x0b12399a, 0x09b8bea9, 0x1474c647, 0x05067671, 0x0fde903c, 0x0b826ebd, 0x0b9f7f76, 0x0ca33da5, 0x1d5e3af7, 0x01ba6985, 0x0324f35a, 0x097d763a, 0x02ad5357, 0x04c5f275, 0x015d16d8, 0x079c295b, 0x09ffc46a, 0x0c3b5b50, 0x097ececd, 0x0d5e820f, 0x0f48aa8b, 0x0fec1748, 0x171b3b57, 0x0f43dc86, 0x0855f73b, 0x06bd08ee, 0x06edd249, 0x0bdaf826, 0x042ed3c9, 0x1fd2f84b, 0x04dbaf4e, 0x025077f9, 0x0f44ddca, 0x1c935f73, 0x0c842699, 0x011e044d, 0x0f056ce3, 0x0e937e4c, 0x07daf860, 0x024a1408, 0x0020dec3, 0x099bd916, 0x1380ba7b, 0x0bed4220, 0x167dceb8, 0x08029816, 0x0cbdca97, 0x1ebd752a, 0x0f8b60ba, 0x1612f3dd, 0x04b663e2, 0x06b6a941, 0x0a40f072, 0x01754505, 0x0b540df3, 0x02eab7e0, 0x1cf4680d, 0x029f2258, 0x0afa1f03, 0x0e53ef55, 0x02cd7e9d, 0x00691fa1, 0x0eb84f7f, 0x0137ac6d, 0x073dc26c, 0x1f8b2442, 0x001fae69, 0x139bc1a6, 0x00b4a346, 0x0262ad0a, 0x053c2f36, 0x14ed2519, 0x079dee98, 0x08aa86bc, 0x14ae77bc, 0x03abb05f, 0x0aa3cd5e, 0x09ee31b2, 0x1a2a7073, 0x00f899ac, 0x07244c01, 0x0465a1ca, 0x068019d7, 0x1b36ac32, 0x0fc404f3, 0x0c4ccc6a, 0x04335a8f, 0x157b3d67, 0x0e9ab217, 0x09c9edac, 0x007f9202, 0x08b62e6b, 0x1fbee11e, 0x0caa4438, 0x004a549f, 0x05007226, 0x050a32d0, 0x0ff828ad, 0x16f4418e, 0x0eef0729, 0x02fa8057, 0x0b06dd1b, 0x0bc25097, 0x1f14f8a7, 0x0d48e7ea, 0x0ed538fc, 0x059830f1, 0x080b70d2, 0x0a2c74d5, 0x06678003, 0x0b076143, 0x077cad74, 0x10ff4c3e, 0x08805cd3, 0x0f3c285a, 0x0407d9de, 0x085f849a, 0x0114214f, 0x00e910ac, 0x1bf48a26, 0x05393631, 0x0afdff12, 0x0988b5ba, 0x030a704e, 0x07f4f727, 0x0a51c380, 0x06a55468, 0x0132b23d, 0x1f9c36b2, 0x0e14eb23, 0x09ef2a10, 0x06c129cd, 0x0b07273b, 0x0a670ac0, 0x125add8e, 0x003975ab, 0x0ba65b4e, 0x129ee0a8, 0x0a2d67b5, 0x1ff454d6, 0x047fa12a, 0x0df7f86e, 0x02c1f24f, 0x184c5a9e, 0x0daf7be2, 0x0fe423ac, 0x17c96dd0, 0x0ed8aab1, 0x01119bca, 0x07d26724, 0x17e34ff7, 0x0a63e10d, 0x0c126075, 0x09ed8d94, 0x078ace82, 0x01cb1226, 0x05138c22, 0x1e1870b8, 0x00ced4bf, 0x148d21e4, 0x09338116, 0x16521561, 0x03eb8d87, 0x0ab0e93d, 0x18645904, 0x0cad899f, 0x1bd92a62, 0x01b9ad3c, 0x04be8e53, 0x01f92c2f, 0x1304c5c4, 0x020b7df1, 0x075a937a, 0x1635abd1, 0x09352072, 0x0ec06d1b, 0x03cc9422, 0x0161df3f, 0x0afd8a91, 0x005187b7, 0x01060a32, 0x02103bd7, 0x0c4f04c2, 0x0bf3a74b, 0x0fa80078, 0x032ce03a, 0x160cdc5e, 0x08be8c87, 0x1e22f29e, 0x0ec41144, 0x09aa28b8, 0x1109da6b, 0x055333b7, 0x039a1ec5, 0x0665068b, 0x16882947, 0x080915a1, 0x0ae15ca6, 0x0010c61e, 0x0895a7b8, 0x08b8f87e, 0x0424c2df, 0x14aa5e34, 0x06353fee, 0x1d2753fa, 0x002fc2ee, 0x16e98910, 0x07684b51, 0x03697bf6, 0x0a02e048, 0x04ca174c, 0x1515c70b, 0x0a9c79d3, 0x02df372e, 0x04af92d5, 0x17fdb7f7, 0x03ac8c37, 0x09e67cb8, 0x148effd3, 0x0c4e602c, 0x0bbc4c30, 0x07960cba, 0x0a8d5513, 0x03a31d69, 0x1c1d8cd4, 0x01785db5, 0x07916d08, 0x14dc9509, 0x0a65de26, 0x11f2c366, 0x048a5ae9, 0x1367bd19, 0x02a08549, 0x16eb136d, 0x0a3d5f84, 0x0c40b857, 0x0667bd3b, 0x07d86441, 0x1c69c2f7, 0x05242baa, 0x1ec61842, 0x06bee348, 0x0a835f39, 0x09df3e0a, 0x044ec48b, 0x00844f37, 0x06688bc0, 0x19e967a5, 0x0c465774, 0x006cfb31, 0x089aada5, 0x1d0a9dfe, 0x0be7d063, 0x05a7985f, 0x1145213f, 0x0ffdd79d, 0x1e751ae3, 0x0d428394, 0x1fb558d1, 0x05f323b5, 0x138ac648, 0x0fb7d18d, 0x06c89c8b, 0x150f5231, 0x0f2e1cec, 0x1ba6050e, 0x04657cd5, 0x1ee3d30a, 0x0f722029, 0x1cdcab41, 0x0bb3247a, 0x0bb3b08f, 0x022331aa, 0x00f664c5, 0x0035a036, 0x0939e876, 0x125ec6eb, 0x036c9813, 0x0cec567a, 0x045d40f6, 0x0f374235, 0x03dc3695, 0x09783bdd, 0x122a1b76, 0x0dc6c542, 0x0ec0973b, 0x0ace2fba, 0x001fd92e, 0x0e75fbfa, 0x04f139c9, 0x034054a9, 0x08e8fc4d, 0x0d73813c, 0x0aae1900, 0x0baa8038, 0x0804c7ed, 0x172751fd, 0x095bd7d1, 0x09a0ebc2, 0x0de24fd4, 0x0d90d5b8, 0x1e8127e9, 0x0c85d920, 0x07455da7, 0x0bd78d8a, 0x105d4b59, 0x08cfcadc, 0x0492737d, 0x0a61ace2, 0x0e5b97f8, 0x1ff0861f, 0x0bb128e3, 0x1a77ca9c, 0x00a118a0, 0x14d2df6b, 0x0eb14ed3, 0x036f8674, 0x11e92af1, 0x00a6f902, 0x00bd59ac, 0x0542cc8b, 0x12a396f9, 0x006f199b, 0x07892274, 0x04d2f31b, 0x0c1958a9, 0x0a0b9945, 0x0147d2ae, 0x0f4444c1, 0x0beab06f, 0x1f8644ad, 0x0867ac4f, 0x18913f7b, 0x0122e994, 0x0ee182a5, 0x0c6a7774, 0x0eab4949, 0x0342653f, 0x0c374b22, 0x1fc1a6bc, 0x04efc8ee, 0x06fdb962, 0x0cf2d346, 0x0adaa9ef, 0x1bbbf647, 0x076ba484, 0x0c9171b8, 0x0272df92, 0x142a0c73, 0x0cb3b29e, 0x192b5d61, 0x0d6431bf, 0x08529ab4, 0x12a86a48, 0x04891a80, 0x18e5c3dd, 0x033f48f2, 0x0673126d, 0x02609cd8, 0x1673b33a, 0x09f5b1fc, 0x0c52b6b6, 0x1f194f96, 0x06f861c6, 0x104edc2c, 0x004b779f, 0x1b751c4c, 0x02ed75ac, 0x07590318, 0x0b8530d8, 0x07af3964, 0x13cb6113, 0x0ece2154, 0x1e366165, 0x09912708, 0x1967139e, 0x01928ee3, 0x04138df8, 0x03046045, 0x08dfb07f, 0x150659cd, 0x0451a48d, 0x17001e2b, 0x07e59eb7, 0x168ea3d5, 0x0746447e, 0x16f896a3, 0x0999ff07, 0x0a1157fc, 0x0e5a406e, 0x0a3da2fc, 0x1a877821, 0x0190e971, 0x11cb520b, 0x0105a18f, 0x19fc0443, 0x0f283d66, 0x0b2e11a6, 0x13de2333, 0x06283a7c, 0x0d4adbb9, 0x00327cb5, 0x180dde99, 0x050ea3fb, 0x13c804ce, 0x0d246dc9, 0x0b5c19fc, 0x1957b4ef, 0x0d30d593, 0x1c7bf734, 0x099f097d, 0x02950925, 0x09eb1562, 0x10306345, 0x09cc3d97, 0x00faaee5, 0x11e478e2, 0x08d019d8, 0x1376371c, 0x05156cbf, 0x1b5af9ec, 0x0a91c790, 0x0ff8a777, 0x00fdb390, 0x0490b21e, 0x043bbb15, 0x0b3997e0, 0x00e6369e, 0x08432dc4, 0x0810131e, 0x02ea0ed2, 0x043ed8d0, 0x0d428cce, 0x0784ebf6, 0x1057225c, 0x05a97871, 0x16695f29, 0x07702178, 0x0513de74, 0x0d4bf714, 0x14877f45, 0x01147468, 0x0e81abb1, 0x172963e5, 0x071663a9, 0x1938c51b, 0x0c91f029, 0x10959394, 0x03f7b511, 0x0565083a, 0x0072c5ef, 0x02f453e4, 0x125b035f, 0x0db51e1d, 0x0fe4ac71, 0x0f18be09, 0x0eb38e8f, 0x0f8f1a7b, 0x03a69517, 0x04521252, 0x00ac240e, 0x09e775d5, 0x062381d1, 0x1a0e66fd, 0x018eb08f, 0x1e172d1f, 0x005a40d8, 0x0ec09041, 0x0c5f7d70, 0x0f901fc5, 0x0afdd0b9, 0x085917af, 0x00ebc129, 0x0c3f57c0, 0x1944d70e, 0x0fb594c2, 0x12473a08, 0x0dce7612, 0x05369607, 0x01c6d3fd, 0x02df85bf, 0x06a4144c, 0x014dc8ea, 0x0b1de849, 0x090e6b2d, 0x0339fe61, 0x005638f4, 0x0d1e7786, 0x0e9d3d79, 0x0799a46e, 0x12a4cbf7, 0x0480b9f4, 0x1817daff, 0x0dd89160, 0x043051b0, 0x0367ddb8, 0x035117ff, 0x1b52b9cf, 0x017e186f, 0x0ebca151, 0x0ba32fbb, 0x0382d24d, 0x0c322491, 0x1df2a75b, 0x05e1f14a, 0x0f1caa53, 0x10c63a9b, 0x0117103a, 0x1f0f1991, 0x070e932b, 0x152f0a31, 0x0dac0b7c, 0x01fcebe0, 0x012a6e2f, 0x058b589a, 0x08c8f713, 0x04209944, 0x11f879b7, 0x01b71478, 0x0be6fbe9, 0x04e3b16b, 0x1cb2bfd5, 0x0ac503a2, 0x0612ddb9, 0x1c04a96b, 0x0e93fcba, 0x00ee9668, 0x0491dae7, 0x144b9132, 0x045795ed, 0x0ffb2d8a, 0x017963d5, 0x07031523, 0x05009576, 0x0efdc834, 0x0996e956, 0x01f22536, 0x0fa0d62a, 0x0207281b, 0x13607435, 0x0fc4ce21, 0x001df3c8, 0x05dca88c, 0x04588e13, 0x1a83ff90, 0x07f756c2, 0x180b70fc, 0x0ff7ce85, 0x1e474049, 0x0a0ea29c, 0x09a22922, 0x064be4a7, 0x0f0f808d, 0x055eef1f, 0x0739b197, 0x1ab8faf3, 0x0be56b58, 0x0cb9f785, 0x0da91ba6, 0x0e434b4c, 0x19d102c0, 0x0e5733d2, 0x0204f890, 0x072c0e34, 0x01b7f618, 0x0d393909, 0x10bfc1f0, 0x0123bc78, 0x0fe483ab, 0x0c33b6af, 0x0846bb93, 0x12a5fb87, 0x01f62e47, 0x19f7a811, 0x0736ee4e, 0x0d936a46, 0x0ba539b0, 0x0e1ee8ed, 0x02d46b39, 0x0a3decc4, 0x1ab3c9f6, 0x0fd557c5, 0x1f7a747c, 0x0b32d22a, 0x11924155, 0x00798a8e, 0x089732a4, 0x1da4639a, 0x00cd9060, 0x10e74d6b, 0x0fc623cd, 0x0eb1aa08, 0x00020600, 0x1ea26ec4, 0x06cf0716, 0x0fac7716, 0x1ed30f73, 0x01a6582a, 0x0de07f95, 0x0e2dc272, 0x08814901, 0x0b7f3da3, 0x1af2086d, 0x03f3c2b6, 0x0654a950, 0x134bf5e0, 0x0c30b342, 0x0c38ca0d, 0x0624e513, 0x0c9313d6, 0x0e52e5f1, 0x0a6afe90, 0x09a6d2d5, 0x0bd3ae7d, 0x156f4137, 0x0b8f6df1, 0x1f10fdb6, 0x051e8bff, 0x14dd2719, 0x00ea259a, 0x080c2dbf, 0x0d0aa333, 0x01dd63c0, 0x041db9c9, 0x032803b8, 0x039fad24, 0x0a87e6de, 0x0ef7d3a2, 0x05a17204, 0x063c8289, 0x0d242d78, 0x0f7d7a8d, 0x04c96d66, 0x0f1cdcc0, 0x038a85fe, 0x036a2087, 0x0e528651, 0x079428a6, 0x16c36ea8, 0x0e8be2f4, 0x0ea6ae12, 0x1e786c61, 0x035aaa8a, 0x14ec9fab, 0x0ddbe872, 0x0c4eb10d, 0x0ceb1abe, 0x11a299e6, 0x06455ab5, 0x02f792d2, 0x157be9c1, 0x0f26bd87, 0x06a3440a, 0x0e34c2a7, 0x1cb0bdcc, 0x0c4878b4, 0x1fe5b2c2, 0x0195111d, 0x02ac293f, 0x0678176d, 0x059a5f56, 0x0efdfad8, 0x01f27110, 0x030fc8a2, 0x060c9d3a, 0x09c329f0, 0x0ae29453, 0x0734c5b9, 0x08e890d1, 0x046adc25, 0x0a8039c7, 0x0035abca, 0x1c9f65cc, 0x0a809de7, 0x0e175e96, 0x07be5c91, 0x0024c597, 0x0ffaa253, 0x07413a42, 0x0e261048, 0x0409e8d5, 0x0f7b40b5, 0x0252fdbf, 0x01b71089, 0x02a29628, 0x07679156, 0x1fba9f0d, 0x0e77990a, 0x18148ddf, 0x05144120, 0x11b67253, 0x083b822e, 0x04d8c1a0, 0x03283315, 0x098c08bb, 0x1279402c, 0x0c148f56, 0x12e5abf2, 0x0e57f049, 0x1ec39689, 0x012c7fc3, 0x0146a28f, 0x07c6b729, 0x0f34db77, 0x0c48ba71, 0x04dfe512, 0x0c00e3c0, 0x0675646b, 0x031deab9, 0x00502b7b, 0x00c50cf8, 0x008a7d0b, 0x0fc93e94, 0x13cc9ef7, 0x085b92af, 0x09af8665, 0x0710cece, 0x08c6e80f, 0x0ca51c19, 0x15d5dbc6, 0x06a0f22c, 0x007c1f9b, 0x1550c96d, 0x0f697b42, 0x0d7d47c7, 0x0d44ec32, 0x08f61884, 0x00952a9b, 0x1c10cc89, 0x064e3729, 0x0c870833, 0x07004bfd, 0x00728d45, 0x0d740851, 0x06db3186, 0x02440e5d, 0x0a31ff5f, 0x02545f45, 0x09cefd7e, 0x0e313f97, 0x0cd00aee, 0x002a3695, 0x1425fe18, 0x07adebcf, 0x0c0ff2ee, 0x08ee1dfb, 0x0c57965b, 0x03a2082d, 0x0421f5a4, 0x1b289f84, 0x08da295e, 0x0de5d723, 0x091efa2e, 0x1c746146, 0x0c47ee2c, 0x17f16399, 0x0e13ddc5, 0x09d97ae9, 0x1f7d368c, 0x06b74b71, 0x1cb3b1d9, 0x0de05204, 0x12506dde, 0x059df69a, 0x1efb6211, 0x0bbd00e5, 0x01906e9c, 0x0d465664, 0x0afc13d3, 0x089afc10, 0x024c1a6d, 0x1205b29f, 0x06919200, 0x199e6264, 0x01648b3f, 0x0516890d, 0x09ba9146, 0x04264772, 0x15001545, 0x0b10ecc6, 0x16ffeb46, 0x0ff37161, 0x0c20d05d, 0x000428c2, 0x0cf02863, 0x06a8eb7c, 0x036bacb1, 0x086de39b, 0x0a286b87, 0x1ae0708c, 0x03faee49, 0x0df0217d, 0x0ffdd3ad, 0x067c5bd6, 0x1a35c730, 0x076dc1a4, 0x0d9eb075, 0x0e4e3fbf, 0x10dc719b, 0x0855235d, 0x0476eb6a, 0x02d00dd9, 0x090df3b3, 0x0f18ef2f, 0x0e42472d, 0x04095238, 0x0b25b08c, 0x0b103b58, 0x04ee1ab8, 0x176c4ea7, 0x0d32bbda, 0x04df95df, 0x15726c40, 0x0e6f34b4, 0x005d4161, 0x06e9ef8e, 0x18d6bf5f, 0x0a4735a8, 0x0fa60f2e, 0x0614eeef, 0x0940f92a, 0x13c99b44, 0x0a578b1c, 0x0ab2df62, 0x02edac29, 0x05e3b871, 0x0b9ac60a, 0x128d363d, 0x06515b08, 0x08826053, 0x0064ed96, 0x0b339514, 0x160a8e8c, 0x0d9851d1, 0x1be9187a, 0x0a34d1f9, 0x0f06cd35, 0x0480c6ea, 0x0540bd71, 0x17a20b36, 0x06358227, 0x00b6976f, 0x0865f9cc, 0x1be27ca5, 0x06d8111d, 0x182def8b, 0x087ea924, 0x02d606e5, 0x12005db7, 0x05350113, 0x0b05ce54, 0x00192668, 0x163f2306, 0x043d4624, 0x09ff14e0, 0x03368c10, 0x04bfdd16, 0x08bcdc55, 0x0f3d8894, 0x09dd8c5a, 0x05bf7d98, 0x1d5a2eed, 0x0c1460a7, 0x130c52c7, 0x0e00260b, 0x0846b65a, 0x007fc19d, 0x0388b1cc, 0x1414c825, 0x0b2a7d39, 0x1c77b342, 0x06e6178d, 0x18e89b8f, 0x0b8631a2, 0x0cee7813, 0x1832a764, 0x0fb6cfda, 0x05119984, 0x04ab1f53, 0x1b490dd6, 0x01f211d5, 0x02b9b43f, 0x0074045a, 0x03002eb0, 0x18130cf0, 0x0a241d6b, 0x136a17c7, 0x07fd25f3, 0x0d813683, 0x00578133, 0x095e033f, 0x00f7b02b, 0x0693e5db, 0x19b843c4, 0x0b2e8707, 0x01564183, 0x03be2e5f, 0x0cbd8859, 0x0ab2c885, 0x03079e66, 0x0403aa04, 0x0599ea21, 0x0857cd52, 0x09711d3c, 0x17d39e68, 0x03da18a8, 0x17e28aa2, 0x07938463, 0x01831de7, 0x06d78d46, 0x028254e2, 0x07babbfe, 0x05130b9c, 0x1a20760a, 0x01c5f251, 0x0c70532a, 0x061d3503, 0x16e1cf24, 0x0c8c1e94, 0x0c868860, 0x01c5eb82, 0x0e162c7a, 0x18fee88a, 0x08e8fce2, 0x1ebb7e1d, 0x07ac5da7, 0x14855068, 0x06e6a716, 0x0844fb58, 0x0b0a6bb0, 0x001eef1f, 0x02f69ae5, 0x0ad8f276, 0x16404117, 0x0621706b, 0x10051c03, 0x08fe47f2, 0x07483eec, 0x11013d7b, 0x099e3296, 0x0f32f18f, 0x08f599ac, 0x0f72e092, 0x087e9c5c, 0x1b674531, 0x0bee4fb3, 0x0852e5c2, 0x12922649, 0x0bb1c0ce, 0x1ea170de, 0x0521942c, 0x1611bfbe, 0x0d9a74b0, 0x1991064a, 0x0f611762, 0x026008e3, 0x0325d940, 0x01ea0d2f, 0x00b72f7c, 0x0f71eb3c, 0x1498a20d, 0x04bf5362, 0x18fb9274, 0x0c2658a8, 0x00e8fac4, 0x1b568c8a, 0x01087183, 0x0fe9459a, 0x0d38d11b, 0x03447b1a, 0x0c357d35, 0x13d20fe0, 0x075cfce2, 0x09d23179, 0x05cf14be, 0x0f0be702, 0x03139625, 0x047fc6e5, 0x1a8b261b, 0x0d39be1f, 0x030b28c0, 0x031bbd96, 0x06af5ed7, 0x0157cb2f, 0x0d9aa073, 0x00f04639, 0x0d4ceab6, 0x0a27c998, 0x00008699, 0x088f9b07, 0x0a029791, 0x052271e2, 0x160b9870, 0x09d483d5, 0x1607b4da, 0x08d14f54, 0x055c154f, 0x085d247f, 0x1f1c3504, 0x0850a5ed, 0x09810e86, 0x0d880798, 0x0ccf48ac, 0x0f090feb, 0x010bdd82, 0x05ead055, 0x03a4e143, 0x0a8f0c3d, 0x0a6e7a6c, 0x0edbd182, 0x0cefd77e, 0x0c54ae35, 0x188c42ba, 0x0f6c85b8, 0x141bbceb, 0x0b5acdf2, 0x1e7159fc, 0x0109af8b, 0x085e0a6c, 0x0a701b96, 0x00d35faa, 0x0e39b8af, 0x08d5ffc9, 0x01d479f7, 0x05a7b8c7, 0x02c787c4, 0x0a2e0196, 0x0d1ee22f, 0x022c73e8, 0x007550d2, 0x1425133b, 0x0d25a759, 0x16008524, 0x04093e40, 0x1d27caf5, 0x0d435a9e, 0x043227c9, 0x0e113f3b, 0x0adbc790, 0x0200a625, 0x0591ae49, 0x1b25097a, 0x02cb3435, 0x1186d785, 0x04ec35ac, 0x0954604d, 0x17f5bd0c, 0x0bfe35d2, 0x166e5de9, 0x0464394f, 0x07d725e9, 0x0fae9b8f, 0x08c64a8a, 0x0f8bd057, 0x0c96e21a, 0x173ccc48, 0x0cd27496, 0x03ae414d, 0x012cde61, 0x146c7a61, 0x0f7efa4d, 0x14b606a8, 0x03dbe88d, 0x0a403052, 0x10440f3f, 0x0e7b9b6c, 0x15c09f57, 0x05259254, 0x069fa4a7, 0x0bdaa08d, 0x153d37b9, 0x07a9999f, 0x0e64d6a7, } // Field element operations: // nonZeroToAllOnes returns: // // 0xffffffff for 0 < x <= 2**31 // 0 for x == 0 or x > 2**31. func nonZeroToAllOnes(x uint32) uint32 { return ((x - 1) >> 31) - 1 } // c256ReduceCarry adds a multiple of p in order to cancel |carry|, // which is a term at 2**257. // p = 2^256 - 2^224 + 2^96 + 2^64 -1 // 2**257 = [c256Limbs]uint32{2, 0, 0x1fffff00, 0x7ff, 0, 0, 0, 0x2000000, 0} // // On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28. // On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29. func c256ReduceCarry(inout *[c256Limbs]uint32, carry uint32) { carryMask := nonZeroToAllOnes(carry) inout[0] += carry << 1 inout[2] += 0x20000000 & carryMask inout[2] -= carry << 8 inout[3] += carry << 11 inout[3] -= 1 & carryMask inout[7] += carry << 25 } // c256Sum sets out = in+in2. // // On entry, in[i]+in2[i] must not overflow a 32-bit word. // On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 func c256Sum(out, in, in2 *[c256Limbs]uint32) { carry := uint32(0) for i := 0; ; i++ { out[i] = in[i] + in2[i] out[i] += carry carry = out[i] >> 29 out[i] &= bottom29Bits i++ if i == c256Limbs { break } out[i] = in[i] + in2[i] out[i] += carry carry = out[i] >> 28 out[i] &= bottom28Bits } c256ReduceCarry(out, carry) } const ( two30m2 = 1<<30 - 1<<2 two31m2 = 1<<31 - 1<<2 two30m27m2 = 1<<30 - 1<<27 - 1<<2 two30m13m2 = 1<<30 - 1<<13 - 1<<2 two31p10m2 = 1<<31 + 1<<10 - 1<<2 two31m3 = 1<<31 - 1<<3 ) // c256Zero31 is 0 mod p. var c256Zero31 = [c256Limbs]uint32{two31m3, two30m2, two31p10m2, two30m13m2, two31m2, two30m2, two31m2, two30m27m2, two31m2} // c256Diff sets out = in-in2. // // On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and // // in2[0,2,...] < 2**30, in2[1,3,...] < 2**29. // // On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. func c256Diff(out, in, in2 *[c256Limbs]uint32) { var carry uint32 for i := 0; ; i++ { out[i] = in[i] - in2[i] out[i] += c256Zero31[i] out[i] += carry carry = out[i] >> 29 out[i] &= bottom29Bits i++ if i == c256Limbs { break } out[i] = in[i] - in2[i] out[i] += c256Zero31[i] out[i] += carry carry = out[i] >> 28 out[i] &= bottom28Bits } c256ReduceCarry(out, carry) } // c256ReduceDegree sets out = tmp/R mod p where tmp contains 64-bit words with // the same 29,28,... bit positions as an field element. // // The values in field elements are in Montgomery form: x*R mod p where R = // 2**257. Since we just multiplied two Montgomery values together, the result // is x*y*R*R mod p. We wish to divide by R in order for the result also to be // in Montgomery form. // // On entry: tmp[i] < 2**64 // On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 func c256ReduceDegree(out *[c256Limbs]uint32, tmp [17]uint64) { // The following table may be helpful when reading this code: // // Limb number: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10... // Width (bits): 29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29 // Start bit: 0 | 29| 57| 86|114|143|171|200|228|257|285 // (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285 var tmp2 [18]uint32 var carry, x, xMask uint32 // tmp contains 64-bit words with the same 29,28,29-bit positions as an // field element. So the top of an element of tmp might overlap with // another element two positions down. The following loop eliminates // this overlap. tmp2[0] = uint32(tmp[0]) & bottom29Bits tmp2[1] = uint32(tmp[0]) >> 29 tmp2[1] |= (uint32(tmp[0]>>32) << 3) & bottom28Bits tmp2[1] += uint32(tmp[1]) & bottom28Bits carry = tmp2[1] >> 28 tmp2[1] &= bottom28Bits for i := 2; i < 17; i++ { tmp2[i] = (uint32(tmp[i-2] >> 32)) >> 25 tmp2[i] += (uint32(tmp[i-1])) >> 28 tmp2[i] += (uint32(tmp[i-1]>>32) << 4) & bottom29Bits tmp2[i] += uint32(tmp[i]) & bottom29Bits tmp2[i] += carry carry = tmp2[i] >> 29 tmp2[i] &= bottom29Bits i++ if i == 17 { break } tmp2[i] = uint32(tmp[i-2]>>32) >> 25 tmp2[i] += uint32(tmp[i-1]) >> 29 tmp2[i] += ((uint32(tmp[i-1] >> 32)) << 3) & bottom28Bits tmp2[i] += uint32(tmp[i]) & bottom28Bits tmp2[i] += carry carry = tmp2[i] >> 28 tmp2[i] &= bottom28Bits } tmp2[17] = uint32(tmp[15]>>32) >> 25 tmp2[17] += uint32(tmp[16]) >> 29 tmp2[17] += uint32(tmp[16]>>32) << 3 tmp2[17] += carry // for l := 0; l < 18; l++ { // fmt.Printf("%08x ", l) // } // fmt.Println("\n----------------------------------------------------------------------------") // Montgomery elimination of terms: // // Since R is 2**257, we can divide by R with a bitwise shift if we can // ensure that the right-most 257 bits are all zero. We can make that true // by adding multiplies of p without affecting the value. // // So we eliminate limbs from right to left. Since the bottom 29 bits of p // are all ones, then by adding tmp2[0]*p to tmp2 we'll make tmp2[0] == 0. // We can do that for 8 further limbs and then right shift to eliminate the // extra factor of R. // c256P = [c256Limbs]uint32{0x1fffffff, 0xfffffff, 0x7f, 0xffffc00, 0x1fffffff, 0xfffffff, 0x1fffffff, 0xeffffff, 0xfffffff} // 0 1 2 3 4 5 6 7 8 // =={2**29-1, 2**28-1, 2**7-1, 2**28-2**10, 2**29-1, 2**28-1, 2**29-1, 2**28-2**24-1, 2**28-1} for i := 0; i < 8; i += 2 { // tmp2[i] maybe > 2**29, fix it first tmp2[i+1] += tmp2[i] >> 29 x = tmp2[i] & bottom29Bits // x is the really digital of tmp2[0], now plus x*p xMask = nonZeroToAllOnes(x) tmp2[i] = 0 // carry = x // tmp2[i+2] += x + 2**7 * x - x = 2**7 * x // tmp2[10] may overflow // var xxx uint64 = uint64(x) // xxx = xxx << 7 // xxx += uint64(tmp2[i+2]) // tmp2[i+2] = uint32(xxx & bottom29Bits) // tmp2[i+3] += uint32(xxx >> 29) tmp2[i+2] += (x << 7) & bottom29Bits // carry = x >> 22 // tmp2[i+3] += x>>22 + 2**28*x - 2**10*x = 2**28 + x>>22 - 2**10*x + (x-1)*2**28 tmp2[i+3] += (x >> 22) tmp2[i+3] += 0x10000000 & xMask tmp2[i+3] -= (x << 10) & bottom28Bits // carry = x-1-(x>>18) // tmp2[i+4] += (2**29 - 1) * x + x - 1 - (x>>18) = 2**29 - 1 - (x>>18) + (x-1)*2**29 tmp2[i+4] += 0x1fffffff & xMask tmp2[i+4] -= (x >> 18) // fmt.Printf("xxx=%016x\n", xxx) // fmt.Printf("x=%08x\n", x) // carry = x-1 // tmp2[i+5] += x-1 + 2**28*x - x = 2**28 - 1 + (x-1)*2**28 tmp2[i+5] += 0xfffffff & xMask // carry = x-1 // tmp2[i+6] += x-1 + 2**29*x - x = 2**29 - 1 + (x-1)*2**29 tmp2[i+6] += 0x1fffffff & xMask // carry = x-1 // tmp2[i+7] += x-1 + 2**28*x - 2**24*x - x = 2**28-1 - 2**24*x + (x-1)*2**28 tmp2[i+7] += 0xfffffff & xMask tmp2[i+7] -= (x << 24) & bottom28Bits // carry = x-1 - (x>>4) // tmp2[i+8] += x-1-(x>>4) + 2**28*x - x = 2**28*x - 1 - (x>>4) /////////////////////////////// // tmp2[i+8] += (x << 28) & bottom29Bits // tmp2[i+8] -= (x >> 4) // tmp2[i+8] -= 1 & xMask // tmp2[i+9] += x >> 1 // var xxx uint64 = uint64(x) << 28 // xxx -= uint64(1 & xMask) // xxx -= uint64(x) >> 4 // tmp2[i+8] += uint32(xxx & bottom29Bits) // tmp2[i+9] += uint32(xxx >> 29) tmp2[i+8] += 0xfffffff & xMask tmp2[i+8] -= x >> 4 tmp2[i+8] += ((x - 1) << 28) & bottom29Bits & xMask tmp2[i+9] += ((x - 1) >> 1) & xMask // half----------------------------------------------------------- // 28 // 0xfffffff, 0x1fffffff, 0x7f, 0x1ffff800, 0xfffffff, 0x1fffffff, 0xfffffff, 0x1dffffff, 0xfffffff // 2**28-1 2**29-1 2**7-1 2**29-2**11 2**28-1 2**29-1 2**28-1 2**29-2**25-1 2**28-1 // 1 2 3 4 5 6 7 8 9 tmp2[i+2] += tmp2[i+1] >> 28 x = tmp2[i+1] & bottom28Bits xMask = nonZeroToAllOnes(x) tmp2[i+1] = 0 tmp2[i+3] += (x << 7) & bottom28Bits // xxx = uint64(x >> 21) // xxx += (uint64(x) << 29) // xxx -= uint64(x >> 11) // tmp2[i+4] += uint32(xxx & bottom29Bits) // tmp2[i+5] += uint32(xxx >> 29) tmp2[i+4] += (x >> 21) tmp2[i+4] += 0x20000000 & xMask tmp2[i+4] -= (x << 11) & bottom29Bits // fmt.Printf("xxx=%016x\n", xxx) // fmt.Printf("x=%08x\n", x) // fmt.Printf("tmp2[%d]=%08x\n", i+4, tmp2[i+4]) // carry = x-1 - x>>18 tmp2[i+5] += 0xfffffff & xMask tmp2[i+5] -= (x >> 18) tmp2[i+6] += 0x1fffffff & xMask tmp2[i+7] += 0xfffffff & xMask //carry = x-1 // + 2**29*x -2**25*x -1 = 2**29 - 1 - 2**25*x + (x-1)*2**29 tmp2[i+8] += 0x1fffffff & xMask tmp2[i+8] -= (x << 25) & bottom29Bits // carry = x-1 - x>>4 // 2**28*x - 1 - x>>4 // xxx = uint64(x) // xxx = (xxx << 28) - 1 - (xxx >> 4) // tmp2[i+9] += uint32(xxx & bottom28Bits) // tmp2[i+10] += uint32(xxx >> 28) // fmt.Printf("tmp2[i+9] = %08x ", tmp2[i+9]) tmp2[i+9] += 0xfffffff & xMask tmp2[i+9] -= x >> 4 // fmt.Printf("%08x\n", tmp2[i+9]) // fmt.Println(i, tmp2[i+10]) tmp2[i+10] += (x - 1) & xMask } // for last half tmp2[9] += tmp2[8] >> 29 x = tmp2[8] & bottom29Bits // x is the really digital of tmp2[0], now plus x*p xMask = nonZeroToAllOnes(x) tmp2[8] = 0 // carry = x // tmp2[i+2] += x + 2**7 * x - x = 2**7 * x // tmp2[10] may overflow // tmp2[8+2] += (x << 7) & bottom29Bits // xxx := uint64(x)<<7 + uint64(tmp2[10]) // tmp2[10] = uint32(xxx & bottom29Bits) // tmp2[11] += uint32(xxx >> 29) tmp2[11] += tmp2[10]>>29 + x>>22 tmp2[10] = tmp2[10]&bottom29Bits + (x<<7)&bottom29Bits // carry already handled // tmp2[8+3] += x>>22 + 2**28*x - 2**10*x = 2**28 + x>>22 - 2**10*x + (x-1)*2**28 tmp2[8+3] += 0x10000000 & xMask tmp2[8+3] -= (x << 10) & bottom28Bits // carry = x-1-(x>>18) // tmp2[8+4] += (2**29 - 1) * x + x - 1 - (x>>18) = 2**29 - 1 - (x>>18) + (x-1)*2**29 tmp2[8+4] += 0x1fffffff & xMask tmp2[8+4] -= (x >> 18) // fmt.Printf("xxx=%016x\n", xxx) // fmt.Printf("x=%08x\n", x) // carry = x-1 // tmp2[8+5] += x-1 + 2**28*x - x = 2**28 - 1 + (x-1)*2**28 tmp2[8+5] += 0xfffffff & xMask // carry = x-1 // tmp2[8+6] += x-1 + 2**29*x - x = 2**29 - 1 + (x-1)*2**29 tmp2[8+6] += 0x1fffffff & xMask // carry = x-1 // tmp2[8+7] += x-1 + 2**28*x - 2**24*x - x = 2**28-1 - 2**24*x + (x-1)*2**28 tmp2[8+7] += 0xfffffff & xMask tmp2[8+7] -= (x << 24) & bottom28Bits // carry = x-1 - (x>>4) // tmp2[8+8] += x-1-(x>>4) + 2**28*x - x = 2**28*x - 1 - (x>>4) /////////////////////////////// // tmp2[8+8] += (x << 28) & bottom29Bits // tmp2[8+8] -= (x >> 4) // tmp2[8+8] -= 1 & xMask // tmp2[8+9] += x >> 1 // var xxx uint64 = uint64(x) << 28 // xxx -= uint64(1 & xMask) // xxx -= uint64(x) >> 4 // tmp2[8+8] += uint32(xxx & bottom29Bits) // tmp2[8+9] += uint32(xxx >> 29) tmp2[8+8] += 0xfffffff & xMask tmp2[8+8] -= (x >> 4) tmp2[8+8] += ((x - 1) << 28) & bottom29Bits & xMask tmp2[8+9] += ((x - 1) >> 1) & xMask // We merge the right shift with a carry chain. The words above 2**257 have // widths of 28,29,... which we need to correct when copying them down. carry = 0 for i := 0; i < 8; i++ { // The maximum value of tmp2[i + 9] occurs on the first iteration and // is < 2**30+2**29+2**28. Adding 2**29 (from tmp2[i + 10]) is // therefore safe. out[i] = tmp2[i+9] // fmt.Printf("%d %08x\n", i, out[i]) out[i] += carry // fmt.Printf("%d %08x\n", i, out[i]) out[i] += (tmp2[i+10] << 28) & bottom29Bits // fmt.Printf("%d %08x\n", i, out[i]) carry = out[i] >> 29 out[i] &= bottom29Bits i++ out[i] = tmp2[i+9] >> 1 // fmt.Printf("%d %08x\n", i, out[i]) out[i] += carry // fmt.Printf("%d %08x\n", i, out[i]) carry = out[i] >> 28 out[i] &= bottom28Bits } out[8] = tmp2[17] out[8] += carry carry = out[8] >> 29 out[8] &= bottom29Bits c256ReduceCarry(out, carry) } // c256Square sets out=in*in. // // On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29. // On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. func c256Square(out, in *[c256Limbs]uint32) { var tmp [17]uint64 tmp[0] = uint64(in[0]) * uint64(in[0]) tmp[1] = uint64(in[0]) * (uint64(in[1]) << 1) tmp[2] = uint64(in[0])*(uint64(in[2])<<1) + uint64(in[1])*(uint64(in[1])<<1) tmp[3] = uint64(in[0])*(uint64(in[3])<<1) + uint64(in[1])*(uint64(in[2])<<1) tmp[4] = uint64(in[0])*(uint64(in[4])<<1) + uint64(in[1])*(uint64(in[3])<<2) + uint64(in[2])*uint64(in[2]) tmp[5] = uint64(in[0])*(uint64(in[5])<<1) + uint64(in[1])*(uint64(in[4])<<1) + uint64(in[2])*(uint64(in[3])<<1) tmp[6] = uint64(in[0])*(uint64(in[6])<<1) + uint64(in[1])*(uint64(in[5])<<2) + uint64(in[2])*(uint64(in[4])<<1) + uint64(in[3])*(uint64(in[3])<<1) tmp[7] = uint64(in[0])*(uint64(in[7])<<1) + uint64(in[1])*(uint64(in[6])<<1) + uint64(in[2])*(uint64(in[5])<<1) + uint64(in[3])*(uint64(in[4])<<1) // tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60, // which is < 2**64 as required. tmp[8] = uint64(in[0])*(uint64(in[8])<<1) + uint64(in[1])*(uint64(in[7])<<2) + uint64(in[2])*(uint64(in[6])<<1) + uint64(in[3])*(uint64(in[5])<<2) + uint64(in[4])*uint64(in[4]) tmp[9] = uint64(in[1])*(uint64(in[8])<<1) + uint64(in[2])*(uint64(in[7])<<1) + uint64(in[3])*(uint64(in[6])<<1) + uint64(in[4])*(uint64(in[5])<<1) tmp[10] = uint64(in[2])*(uint64(in[8])<<1) + uint64(in[3])*(uint64(in[7])<<2) + uint64(in[4])*(uint64(in[6])<<1) + uint64(in[5])*(uint64(in[5])<<1) tmp[11] = uint64(in[3])*(uint64(in[8])<<1) + uint64(in[4])*(uint64(in[7])<<1) + uint64(in[5])*(uint64(in[6])<<1) tmp[12] = uint64(in[4])*(uint64(in[8])<<1) + uint64(in[5])*(uint64(in[7])<<2) + uint64(in[6])*uint64(in[6]) tmp[13] = uint64(in[5])*(uint64(in[8])<<1) + uint64(in[6])*(uint64(in[7])<<1) tmp[14] = uint64(in[6])*(uint64(in[8])<<1) + uint64(in[7])*(uint64(in[7])<<1) tmp[15] = uint64(in[7]) * (uint64(in[8]) << 1) tmp[16] = uint64(in[8]) * uint64(in[8]) c256ReduceDegree(out, tmp) } // c256Mul sets out=in*in2. // // On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and // // in2[0,2,...] < 2**30, in2[1,3,...] < 2**29. // // On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. func c256Mul(out, in, in2 *[c256Limbs]uint32) { var tmp [17]uint64 tmp[0] = uint64(in[0]) * uint64(in2[0]) tmp[1] = uint64(in[0])*(uint64(in2[1])<<0) + uint64(in[1])*(uint64(in2[0])<<0) tmp[2] = uint64(in[0])*(uint64(in2[2])<<0) + uint64(in[1])*(uint64(in2[1])<<1) + uint64(in[2])*(uint64(in2[0])<<0) tmp[3] = uint64(in[0])*(uint64(in2[3])<<0) + uint64(in[1])*(uint64(in2[2])<<0) + uint64(in[2])*(uint64(in2[1])<<0) + uint64(in[3])*(uint64(in2[0])<<0) tmp[4] = uint64(in[0])*(uint64(in2[4])<<0) + uint64(in[1])*(uint64(in2[3])<<1) + uint64(in[2])*(uint64(in2[2])<<0) + uint64(in[3])*(uint64(in2[1])<<1) + uint64(in[4])*(uint64(in2[0])<<0) tmp[5] = uint64(in[0])*(uint64(in2[5])<<0) + uint64(in[1])*(uint64(in2[4])<<0) + uint64(in[2])*(uint64(in2[3])<<0) + uint64(in[3])*(uint64(in2[2])<<0) + uint64(in[4])*(uint64(in2[1])<<0) + uint64(in[5])*(uint64(in2[0])<<0) tmp[6] = uint64(in[0])*(uint64(in2[6])<<0) + uint64(in[1])*(uint64(in2[5])<<1) + uint64(in[2])*(uint64(in2[4])<<0) + uint64(in[3])*(uint64(in2[3])<<1) + uint64(in[4])*(uint64(in2[2])<<0) + uint64(in[5])*(uint64(in2[1])<<1) + uint64(in[6])*(uint64(in2[0])<<0) tmp[7] = uint64(in[0])*(uint64(in2[7])<<0) + uint64(in[1])*(uint64(in2[6])<<0) + uint64(in[2])*(uint64(in2[5])<<0) + uint64(in[3])*(uint64(in2[4])<<0) + uint64(in[4])*(uint64(in2[3])<<0) + uint64(in[5])*(uint64(in2[2])<<0) + uint64(in[6])*(uint64(in2[1])<<0) + uint64(in[7])*(uint64(in2[0])<<0) // tmp[8] has the greatest value but doesn't overflow. See logic in // c256Square. tmp[8] = uint64(in[0])*(uint64(in2[8])<<0) + uint64(in[1])*(uint64(in2[7])<<1) + uint64(in[2])*(uint64(in2[6])<<0) + uint64(in[3])*(uint64(in2[5])<<1) + uint64(in[4])*(uint64(in2[4])<<0) + uint64(in[5])*(uint64(in2[3])<<1) + uint64(in[6])*(uint64(in2[2])<<0) + uint64(in[7])*(uint64(in2[1])<<1) + uint64(in[8])*(uint64(in2[0])<<0) tmp[9] = uint64(in[1])*(uint64(in2[8])<<0) + uint64(in[2])*(uint64(in2[7])<<0) + uint64(in[3])*(uint64(in2[6])<<0) + uint64(in[4])*(uint64(in2[5])<<0) + uint64(in[5])*(uint64(in2[4])<<0) + uint64(in[6])*(uint64(in2[3])<<0) + uint64(in[7])*(uint64(in2[2])<<0) + uint64(in[8])*(uint64(in2[1])<<0) tmp[10] = uint64(in[2])*(uint64(in2[8])<<0) + uint64(in[3])*(uint64(in2[7])<<1) + uint64(in[4])*(uint64(in2[6])<<0) + uint64(in[5])*(uint64(in2[5])<<1) + uint64(in[6])*(uint64(in2[4])<<0) + uint64(in[7])*(uint64(in2[3])<<1) + uint64(in[8])*(uint64(in2[2])<<0) tmp[11] = uint64(in[3])*(uint64(in2[8])<<0) + uint64(in[4])*(uint64(in2[7])<<0) + uint64(in[5])*(uint64(in2[6])<<0) + uint64(in[6])*(uint64(in2[5])<<0) + uint64(in[7])*(uint64(in2[4])<<0) + uint64(in[8])*(uint64(in2[3])<<0) tmp[12] = uint64(in[4])*(uint64(in2[8])<<0) + uint64(in[5])*(uint64(in2[7])<<1) + uint64(in[6])*(uint64(in2[6])<<0) + uint64(in[7])*(uint64(in2[5])<<1) + uint64(in[8])*(uint64(in2[4])<<0) tmp[13] = uint64(in[5])*(uint64(in2[8])<<0) + uint64(in[6])*(uint64(in2[7])<<0) + uint64(in[7])*(uint64(in2[6])<<0) + uint64(in[8])*(uint64(in2[5])<<0) tmp[14] = uint64(in[6])*(uint64(in2[8])<<0) + uint64(in[7])*(uint64(in2[7])<<1) + uint64(in[8])*(uint64(in2[6])<<0) tmp[15] = uint64(in[7])*(uint64(in2[8])<<0) + uint64(in[8])*(uint64(in2[7])<<0) tmp[16] = uint64(in[8]) * (uint64(in2[8]) << 0) c256ReduceDegree(out, tmp) } func c256Assign(out, in *[c256Limbs]uint32) { *out = *in } // c256Invert calculates |out| = |in|^{-1} // // Based on Fermat's Little Theorem: // // a^p = a (mod p) // a^{p-1} = 1 (mod p) // a^{p-2} = a^{-1} (mod p) // // The Loop is fixed, so the consumed time is constant // TODO: can be faster? func c256Invert(out, in *[c256Limbs]uint32) { // set ftmp = 1 * R ftmp := [c256Limbs]uint32{0x2, 0x0, 0x1fffff00, 0x7ff, 0x0, 0x0, 0x0, 0x2000000, 0} // idx[0] is highest bit var idx = [256]int{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, } for _, d := range idx { c256Square(&ftmp, &ftmp) if d == 1 { c256Mul(&ftmp, &ftmp, in) } } c256Assign(out, &ftmp) } // c256Scalar3 sets out=3*out. // // On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. // On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. func c256Scalar3(out *[c256Limbs]uint32) { var carry uint32 for i := 0; ; i++ { out[i] *= 3 out[i] += carry carry = out[i] >> 29 out[i] &= bottom29Bits i++ if i == c256Limbs { break } out[i] *= 3 out[i] += carry carry = out[i] >> 28 out[i] &= bottom28Bits } c256ReduceCarry(out, carry) } // c256Scalar4 sets out=4*out. // // On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. // On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. func c256Scalar4(out *[c256Limbs]uint32) { var carry, nextCarry uint32 for i := 0; ; i++ { nextCarry = out[i] >> 27 out[i] <<= 2 out[i] &= bottom29Bits out[i] += carry carry = nextCarry + (out[i] >> 29) out[i] &= bottom29Bits i++ if i == c256Limbs { break } nextCarry = out[i] >> 26 out[i] <<= 2 out[i] &= bottom28Bits out[i] += carry carry = nextCarry + (out[i] >> 28) out[i] &= bottom28Bits } c256ReduceCarry(out, carry) } // c256Scalar8 sets out=8*out. // // On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. // On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. func c256Scalar8(out *[c256Limbs]uint32) { var carry, nextCarry uint32 for i := 0; ; i++ { nextCarry = out[i] >> 26 out[i] <<= 3 out[i] &= bottom29Bits out[i] += carry carry = nextCarry + (out[i] >> 29) out[i] &= bottom29Bits i++ if i == c256Limbs { break } nextCarry = out[i] >> 25 out[i] <<= 3 out[i] &= bottom28Bits out[i] += carry carry = nextCarry + (out[i] >> 28) out[i] &= bottom28Bits } c256ReduceCarry(out, carry) } // Group operations: // // Elements of the elliptic curve group are represented in Jacobian // coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in // Jacobian form. // c256PointDouble sets {xOut,yOut,zOut} = 2*{x,y,z}. // // See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l func c256PointDouble(xOut, yOut, zOut, x, y, z *[c256Limbs]uint32) { var delta, gamma, alpha, beta, tmp, tmp2 [c256Limbs]uint32 c256Square(&delta, z) c256Square(&gamma, y) c256Mul(&beta, x, &gamma) c256Sum(&tmp, x, &delta) c256Diff(&tmp2, x, &delta) c256Mul(&alpha, &tmp, &tmp2) c256Scalar3(&alpha) c256Sum(&tmp, y, z) c256Square(&tmp, &tmp) c256Diff(&tmp, &tmp, &gamma) c256Diff(zOut, &tmp, &delta) c256Scalar4(&beta) c256Square(xOut, &alpha) c256Diff(xOut, xOut, &beta) c256Diff(xOut, xOut, &beta) c256Diff(&tmp, &beta, xOut) c256Mul(&tmp, &alpha, &tmp) c256Square(&tmp2, &gamma) c256Scalar8(&tmp2) c256Diff(yOut, &tmp, &tmp2) } // c256PointAddMixed sets {xOut,yOut,zOut} = {x1,y1,z1} + {x2,y2,1}. // (i.e. the second point is affine.) // // See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl // // Note that this function does not handle P+P, infinity+P nor P+infinity // correctly. func c256PointAddMixed(xOut, yOut, zOut, x1, y1, z1, x2, y2 *[c256Limbs]uint32) { var z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp [c256Limbs]uint32 c256Square(&z1z1, z1) c256Sum(&tmp, z1, z1) c256Mul(&u2, x2, &z1z1) c256Mul(&z1z1z1, z1, &z1z1) c256Mul(&s2, y2, &z1z1z1) c256Diff(&h, &u2, x1) c256Sum(&i, &h, &h) c256Square(&i, &i) c256Mul(&j, &h, &i) c256Diff(&r, &s2, y1) c256Sum(&r, &r, &r) c256Mul(&v, x1, &i) c256Mul(zOut, &tmp, &h) c256Square(&rr, &r) c256Diff(xOut, &rr, &j) c256Diff(xOut, xOut, &v) c256Diff(xOut, xOut, &v) c256Diff(&tmp, &v, xOut) c256Mul(yOut, &tmp, &r) c256Mul(&tmp, y1, &j) c256Diff(yOut, yOut, &tmp) c256Diff(yOut, yOut, &tmp) } // c256PointAdd sets {xOut,yOut,zOut} = {x1,y1,z1} + {x2,y2,z2}. // // See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl // // Note that this function does not handle P+P, infinity+P nor P+infinity // correctly. func c256PointAdd(xOut, yOut, zOut, x1, y1, z1, x2, y2, z2 *[c256Limbs]uint32) { var z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp [c256Limbs]uint32 c256Square(&z1z1, z1) c256Square(&z2z2, z2) c256Mul(&u1, x1, &z2z2) c256Sum(&tmp, z1, z2) c256Square(&tmp, &tmp) c256Diff(&tmp, &tmp, &z1z1) c256Diff(&tmp, &tmp, &z2z2) c256Mul(&z2z2z2, z2, &z2z2) c256Mul(&s1, y1, &z2z2z2) c256Mul(&u2, x2, &z1z1) c256Mul(&z1z1z1, z1, &z1z1) c256Mul(&s2, y2, &z1z1z1) c256Diff(&h, &u2, &u1) c256Sum(&i, &h, &h) c256Square(&i, &i) c256Mul(&j, &h, &i) c256Diff(&r, &s2, &s1) c256Sum(&r, &r, &r) c256Mul(&v, &u1, &i) c256Mul(zOut, &tmp, &h) c256Square(&rr, &r) c256Diff(xOut, &rr, &j) c256Diff(xOut, xOut, &v) c256Diff(xOut, xOut, &v) c256Diff(&tmp, &v, xOut) c256Mul(yOut, &tmp, &r) c256Mul(&tmp, &s1, &j) c256Diff(yOut, yOut, &tmp) c256Diff(yOut, yOut, &tmp) } // c256CopyConditional sets out=in if mask = 0xffffffff in constant time. // // On entry: mask is either 0 or 0xffffffff. func c256CopyConditional(out, in *[c256Limbs]uint32, mask uint32) { for i := 0; i < c256Limbs; i++ { tmp := mask & (in[i] ^ out[i]) out[i] ^= tmp } } // c256SelectAffinePoint sets {out_x,out_y} to the index'th entry of table. // On entry: index < 16, table[0] must be zero. func c256SelectAffinePoint(xOut, yOut *[c256Limbs]uint32, table []uint32, index uint32) { for i := range xOut { xOut[i] = 0 } for i := range yOut { yOut[i] = 0 } for i := uint32(1); i < 16; i++ { mask := i ^ index mask |= mask >> 2 mask |= mask >> 1 mask &= 1 mask-- for j := range xOut { xOut[j] |= table[0] & mask table = table[1:] } for j := range yOut { yOut[j] |= table[0] & mask table = table[1:] } } } // c256SelectJacobianPoint sets {out_x,out_y,out_z} to the index'th entry of // table. // On entry: index < 16, table[0] must be zero. func c256SelectJacobianPoint(xOut, yOut, zOut *[c256Limbs]uint32, table *[16][3][c256Limbs]uint32, index uint32) { for i := range xOut { xOut[i] = 0 } for i := range yOut { yOut[i] = 0 } for i := range zOut { zOut[i] = 0 } // The implicit value at index 0 is all zero. We don't need to perform that // iteration of the loop because we already set out_* to zero. for i := uint32(1); i < 16; i++ { mask := i ^ index mask |= mask >> 2 mask |= mask >> 1 mask &= 1 mask-- for j := range xOut { xOut[j] |= table[i][0][j] & mask } for j := range yOut { yOut[j] |= table[i][1][j] & mask } for j := range zOut { zOut[j] |= table[i][2][j] & mask } } } // c256GetBit returns the bit'th bit of scalar. func c256GetBit(scalar *[32]uint8, bit uint) uint32 { return uint32(((scalar[bit>>3]) >> (bit & 7)) & 1) } // c256ScalarBaseMult sets {xOut,yOut,zOut} = scalar*G where scalar is a // little-endian number. Note that the value of scalar must be less than the // order of the group. func c256ScalarBaseMult(xOut, yOut, zOut *[c256Limbs]uint32, scalar *[32]uint8) { if true { c256ScalarBaseMult4(xOut, yOut, zOut, scalar) } else { // FIXME not ok c256ScalarBaseMult8(xOut, yOut, zOut, scalar) } } func c256ScalarBaseMult4(xOut, yOut, zOut *[c256Limbs]uint32, scalar *[32]uint8) { nIsInfinityMask := ^uint32(0) var pIsNoninfiniteMask, mask, tableOffset uint32 var px, py, tx, ty, tz [c256Limbs]uint32 for i := range xOut { xOut[i] = 0 } for i := range yOut { yOut[i] = 0 } for i := range zOut { zOut[i] = 0 } // The loop adds bits at positions 0, 64, 128 and 192, followed by // positions 32,96,160 and 224 and does this 32 times. for i := uint(0); i < 32; i++ { if i != 0 { c256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) } tableOffset = 0 for j := uint(0); j <= 32; j += 32 { bit0 := c256GetBit(scalar, 31-i+j) bit1 := c256GetBit(scalar, 95-i+j) bit2 := c256GetBit(scalar, 159-i+j) bit3 := c256GetBit(scalar, 223-i+j) index := bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3) c256SelectAffinePoint(&px, &py, c256Precomputed[tableOffset:], index) tableOffset += 30 * c256Limbs // Since scalar is less than the order of the group, we know that // {xOut,yOut,zOut} != {px,py,1}, unless both are zero, which we handle // below. c256PointAddMixed(&tx, &ty, &tz, xOut, yOut, zOut, &px, &py) // The result of pointAddMixed is incorrect if {xOut,yOut,zOut} is zero // (a.k.a. the point at infinity). We handle that situation by // copying the point from the table. c256CopyConditional(xOut, &px, nIsInfinityMask) c256CopyConditional(yOut, &py, nIsInfinityMask) c256CopyConditional(zOut, &c256One, nIsInfinityMask) // Equally, the result is also wrong if the point from the table is // zero, which happens when the index is zero. We handle that by // only copying from {tx,ty,tz} to {xOut,yOut,zOut} if index != 0. pIsNoninfiniteMask = nonZeroToAllOnes(index) mask = pIsNoninfiniteMask & ^nIsInfinityMask c256CopyConditional(xOut, &tx, mask) c256CopyConditional(yOut, &ty, mask) c256CopyConditional(zOut, &tz, mask) // If p was not zero, then n is now non-zero. nIsInfinityMask &^= pIsNoninfiniteMask } } } func c256ScalarBaseMult8(xOut, yOut, zOut *[c256Limbs]uint32, scalar *[32]uint8) { var px, py [c256Limbs]uint32 for i := range xOut { xOut[i] = 0 } for i := range yOut { yOut[i] = 0 } for i := range zOut { zOut[i] = 0 } for i := uint(0); i < 32; i++ { if i != 0 { c256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) } bit0 := c256GetBit(scalar, uint(31-i)) bit1 := c256GetBit(scalar, uint(63-i)) bit2 := c256GetBit(scalar, uint(95-i)) bit3 := c256GetBit(scalar, uint(127-i)) bit4 := c256GetBit(scalar, uint(159-i)) bit5 := c256GetBit(scalar, uint(191-i)) bit6 := c256GetBit(scalar, uint(223-i)) bit7 := c256GetBit(scalar, uint(255-i)) index := bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3) | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7) copy(px[:], c256Precomputed8[2*index*9:2*index*9+9]) copy(py[:], c256Precomputed8[2*index*9+9:2*index*9+18]) c256PointAddMixed(xOut, yOut, zOut, xOut, yOut, zOut, &px, &py) } } // c256PointToAffine converts a Jacobian point to an affine point. If the input // is the point at infinity then it returns (0, 0) in constant time. func c256PointToAffine(xOut, yOut, x, y, z *[c256Limbs]uint32) { var zInv, zInvSq [c256Limbs]uint32 c256Invert(&zInv, z) c256Square(&zInvSq, &zInv) c256Mul(xOut, x, &zInvSq) c256Mul(&zInv, &zInv, &zInvSq) c256Mul(yOut, y, &zInv) } // c256ToAffine returns a pair of *big.Int containing the affine representation // of {x,y,z}. func c256ToAffine(x, y, z *[c256Limbs]uint32) (xOut, yOut *big.Int) { var xx, yy [c256Limbs]uint32 c256PointToAffine(&xx, &yy, x, y, z) return c256ToBig(&xx), c256ToBig(&yy) } // c256ScalarMult sets {xOut,yOut,zOut} = scalar*{x,y}. func c256ScalarMult(xOut, yOut, zOut, x, y *[c256Limbs]uint32, scalar *[32]uint8) { var px, py, pz, tx, ty, tz [c256Limbs]uint32 var precomp [16][3][c256Limbs]uint32 var nIsInfinityMask, index, pIsNoninfiniteMask, mask uint32 // We precompute 0,1,2,... times {x,y}. precomp[1][0] = *x precomp[1][1] = *y precomp[1][2] = c256One for i := 2; i < 16; i += 2 { c256PointDouble(&precomp[i][0], &precomp[i][1], &precomp[i][2], &precomp[i/2][0], &precomp[i/2][1], &precomp[i/2][2]) c256PointAddMixed(&precomp[i+1][0], &precomp[i+1][1], &precomp[i+1][2], &precomp[i][0], &precomp[i][1], &precomp[i][2], x, y) } for i := range xOut { xOut[i] = 0 } for i := range yOut { yOut[i] = 0 } for i := range zOut { zOut[i] = 0 } nIsInfinityMask = ^uint32(0) // We add in a window of four bits each iteration and do this 64 times. for i := 0; i < 64; i++ { if i != 0 { c256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) c256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) c256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) c256PointDouble(xOut, yOut, zOut, xOut, yOut, zOut) } index = uint32(scalar[31-i/2]) if (i & 1) == 1 { index &= 15 } else { index >>= 4 } // See the comments in scalarBaseMult about handling infinities. c256SelectJacobianPoint(&px, &py, &pz, &precomp, index) c256PointAdd(&tx, &ty, &tz, xOut, yOut, zOut, &px, &py, &pz) c256CopyConditional(xOut, &px, nIsInfinityMask) c256CopyConditional(yOut, &py, nIsInfinityMask) c256CopyConditional(zOut, &pz, nIsInfinityMask) pIsNoninfiniteMask = nonZeroToAllOnes(index) mask = pIsNoninfiniteMask & ^nIsInfinityMask c256CopyConditional(xOut, &tx, mask) c256CopyConditional(yOut, &ty, mask) c256CopyConditional(zOut, &tz, mask) nIsInfinityMask &^= pIsNoninfiniteMask } } // c256FromBig sets out = R*in. func c256FromBig(out *[c256Limbs]uint32, in *big.Int) { tmp := new(big.Int).Lsh(in, 257) tmp.Mod(tmp, c256.P) for i := 0; i < c256Limbs; i++ { if bits := tmp.Bits(); len(bits) > 0 { out[i] = uint32(bits[0]) & bottom29Bits } else { out[i] = 0 } tmp.Rsh(tmp, 29) i++ if i == c256Limbs { break } if bits := tmp.Bits(); len(bits) > 0 { out[i] = uint32(bits[0]) & bottom28Bits } else { out[i] = 0 } tmp.Rsh(tmp, 28) } } // c256ToBig returns a *big.Int containing the value of in. func c256ToBig(in *[c256Limbs]uint32) *big.Int { result, tmp := new(big.Int), new(big.Int) result.SetInt64(int64(in[c256Limbs-1])) for i := c256Limbs - 2; i >= 0; i-- { if (i & 1) == 0 { result.Lsh(result, 29) } else { result.Lsh(result, 28) } tmp.SetInt64(int64(in[i])) result.Add(result, tmp) } result.Mul(result, c256RInverse) // fmt.Println("result=", result) // fmt.Println("P", c256.P) result.Mod(result, c256.P) return result }