http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/go/AES.go
----------------------------------------------------------------------
diff --git a/version22/go/AES.go b/version22/go/AES.go
new file mode 100644
index 0000000..1aeb6d7
--- /dev/null
+++ b/version22/go/AES.go
@@ -0,0 +1,634 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* AES Encryption */ 
+
+package main
+
+//import "fmt"
+
+const aes_ECB int=0
+const aes_CBC int=1
+const aes_CFB1 int=2
+const aes_CFB2 int=3
+const aes_CFB4 int=5
+const aes_OFB1 int=14
+const aes_OFB2 int=15
+const aes_OFB4 int=17
+const aes_OFB8 int=21
+const aes_OFB16 int=29
+const aes_CTR1 int=30
+const aes_CTR2 int=31
+const aes_CTR4 int=33 
+const aes_CTR8 int=37 
+const aes_CTR16 int=45 
+
+var aes_InCo = [...]byte {0xB,0xD,0x9,0xE}  /* Inverse Coefficients */
+
+var aes_ptab = [...]byte {
+     1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53,
+     95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170,
+     229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49,
+     83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205,
+     76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136,
+     131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 
154,
+     181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163,
+     254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160,
+     251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65,
+     195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117,
+     159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 
128,
+     155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84,
+     252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202,
+     69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14,
+     18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23,
+     57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1}
+
+var aes_ltab = [...]byte {
+      0, 255, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3,
+     100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193,
+     125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120,
+     101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142,
+     150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56,
+     102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16,
+     126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186,
+     43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87,
+     175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 
232,
+     44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160,
+     127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183,
+     204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157,
+     151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 
209,
+     83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171,
+     68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165,
+     103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7}
+   
+
+var aes_fbsub = [...]byte {
+     99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
+     202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 
192,
+     183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
+     4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
+     9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
+     83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
+     208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
+     81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
+     205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
+     96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
+     224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
+     231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
+     186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
+     112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
+     225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 
223,
+     140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22}
+    
+var aes_rbsub = [...]byte {
+     82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251,
+     124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203,
+     84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78,
+     8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37,
+     114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 
146,
+     108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132,
+     144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6,
+     208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107,
+     58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 
115,
+     150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 
110,
+     71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27,
+     252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244,
+     31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95,
+     96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239,
+     160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97,
+     23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125}
+    
+
+var aes_rco = [...]byte {1,2,4,8,16,32,64,128,27,54,108,216,171,77,154,47}
+
+var aes_ftable = [...]uint32 {
+    0xa56363c6,0x847c7cf8,0x997777ee,0x8d7b7bf6,0xdf2f2ff,0xbd6b6bd6,
+    0xb16f6fde,0x54c5c591,0x50303060,0x3010102,0xa96767ce,0x7d2b2b56,
+    0x19fefee7,0x62d7d7b5,0xe6abab4d,0x9a7676ec,0x45caca8f,0x9d82821f,
+    0x40c9c989,0x877d7dfa,0x15fafaef,0xeb5959b2,0xc947478e,0xbf0f0fb,
+    0xecadad41,0x67d4d4b3,0xfda2a25f,0xeaafaf45,0xbf9c9c23,0xf7a4a453,
+    0x967272e4,0x5bc0c09b,0xc2b7b775,0x1cfdfde1,0xae93933d,0x6a26264c,
+    0x5a36366c,0x413f3f7e,0x2f7f7f5,0x4fcccc83,0x5c343468,0xf4a5a551,
+    0x34e5e5d1,0x8f1f1f9,0x937171e2,0x73d8d8ab,0x53313162,0x3f15152a,
+    0xc040408,0x52c7c795,0x65232346,0x5ec3c39d,0x28181830,0xa1969637,
+    0xf05050a,0xb59a9a2f,0x907070e,0x36121224,0x9b80801b,0x3de2e2df,
+    0x26ebebcd,0x6927274e,0xcdb2b27f,0x9f7575ea,0x1b090912,0x9e83831d,
+    0x742c2c58,0x2e1a1a34,0x2d1b1b36,0xb26e6edc,0xee5a5ab4,0xfba0a05b,
+    0xf65252a4,0x4d3b3b76,0x61d6d6b7,0xceb3b37d,0x7b292952,0x3ee3e3dd,
+    0x712f2f5e,0x97848413,0xf55353a6,0x68d1d1b9,0x0,0x2cededc1,
+    0x60202040,0x1ffcfce3,0xc8b1b179,0xed5b5bb6,0xbe6a6ad4,0x46cbcb8d,
+    0xd9bebe67,0x4b393972,0xde4a4a94,0xd44c4c98,0xe85858b0,0x4acfcf85,
+    0x6bd0d0bb,0x2aefefc5,0xe5aaaa4f,0x16fbfbed,0xc5434386,0xd74d4d9a,
+    0x55333366,0x94858511,0xcf45458a,0x10f9f9e9,0x6020204,0x817f7ffe,
+    0xf05050a0,0x443c3c78,0xba9f9f25,0xe3a8a84b,0xf35151a2,0xfea3a35d,
+    0xc0404080,0x8a8f8f05,0xad92923f,0xbc9d9d21,0x48383870,0x4f5f5f1,
+    0xdfbcbc63,0xc1b6b677,0x75dadaaf,0x63212142,0x30101020,0x1affffe5,
+    0xef3f3fd,0x6dd2d2bf,0x4ccdcd81,0x140c0c18,0x35131326,0x2fececc3,
+    0xe15f5fbe,0xa2979735,0xcc444488,0x3917172e,0x57c4c493,0xf2a7a755,
+    0x827e7efc,0x473d3d7a,0xac6464c8,0xe75d5dba,0x2b191932,0x957373e6,
+    0xa06060c0,0x98818119,0xd14f4f9e,0x7fdcdca3,0x66222244,0x7e2a2a54,
+    0xab90903b,0x8388880b,0xca46468c,0x29eeeec7,0xd3b8b86b,0x3c141428,
+    0x79dedea7,0xe25e5ebc,0x1d0b0b16,0x76dbdbad,0x3be0e0db,0x56323264,
+    0x4e3a3a74,0x1e0a0a14,0xdb494992,0xa06060c,0x6c242448,0xe45c5cb8,
+    0x5dc2c29f,0x6ed3d3bd,0xefacac43,0xa66262c4,0xa8919139,0xa4959531,
+    0x37e4e4d3,0x8b7979f2,0x32e7e7d5,0x43c8c88b,0x5937376e,0xb76d6dda,
+    0x8c8d8d01,0x64d5d5b1,0xd24e4e9c,0xe0a9a949,0xb46c6cd8,0xfa5656ac,
+    0x7f4f4f3,0x25eaeacf,0xaf6565ca,0x8e7a7af4,0xe9aeae47,0x18080810,
+    0xd5baba6f,0x887878f0,0x6f25254a,0x722e2e5c,0x241c1c38,0xf1a6a657,
+    0xc7b4b473,0x51c6c697,0x23e8e8cb,0x7cdddda1,0x9c7474e8,0x211f1f3e,
+    0xdd4b4b96,0xdcbdbd61,0x868b8b0d,0x858a8a0f,0x907070e0,0x423e3e7c,
+    0xc4b5b571,0xaa6666cc,0xd8484890,0x5030306,0x1f6f6f7,0x120e0e1c,
+    0xa36161c2,0x5f35356a,0xf95757ae,0xd0b9b969,0x91868617,0x58c1c199,
+    0x271d1d3a,0xb99e9e27,0x38e1e1d9,0x13f8f8eb,0xb398982b,0x33111122,
+    0xbb6969d2,0x70d9d9a9,0x898e8e07,0xa7949433,0xb69b9b2d,0x221e1e3c,
+    0x92878715,0x20e9e9c9,0x49cece87,0xff5555aa,0x78282850,0x7adfdfa5,
+    0x8f8c8c03,0xf8a1a159,0x80898909,0x170d0d1a,0xdabfbf65,0x31e6e6d7,
+    0xc6424284,0xb86868d0,0xc3414182,0xb0999929,0x772d2d5a,0x110f0f1e,
+    0xcbb0b07b,0xfc5454a8,0xd6bbbb6d,0x3a16162c}
+
+var aes_rtable = [...]uint32 {
+    0x50a7f451,0x5365417e,0xc3a4171a,0x965e273a,0xcb6bab3b,0xf1459d1f,
+    0xab58faac,0x9303e34b,0x55fa3020,0xf66d76ad,0x9176cc88,0x254c02f5,
+    0xfcd7e54f,0xd7cb2ac5,0x80443526,0x8fa362b5,0x495ab1de,0x671bba25,
+    0x980eea45,0xe1c0fe5d,0x2752fc3,0x12f04c81,0xa397468d,0xc6f9d36b,
+    0xe75f8f03,0x959c9215,0xeb7a6dbf,0xda595295,0x2d83bed4,0xd3217458,
+    0x2969e049,0x44c8c98e,0x6a89c275,0x78798ef4,0x6b3e5899,0xdd71b927,
+    0xb64fe1be,0x17ad88f0,0x66ac20c9,0xb43ace7d,0x184adf63,0x82311ae5,
+    0x60335197,0x457f5362,0xe07764b1,0x84ae6bbb,0x1ca081fe,0x942b08f9,
+    0x58684870,0x19fd458f,0x876cde94,0xb7f87b52,0x23d373ab,0xe2024b72,
+    0x578f1fe3,0x2aab5566,0x728ebb2,0x3c2b52f,0x9a7bc586,0xa50837d3,
+    0xf2872830,0xb2a5bf23,0xba6a0302,0x5c8216ed,0x2b1ccf8a,0x92b479a7,
+    0xf0f207f3,0xa1e2694e,0xcdf4da65,0xd5be0506,0x1f6234d1,0x8afea6c4,
+    0x9d532e34,0xa055f3a2,0x32e18a05,0x75ebf6a4,0x39ec830b,0xaaef6040,
+    0x69f715e,0x51106ebd,0xf98a213e,0x3d06dd96,0xae053edd,0x46bde64d,
+    0xb58d5491,0x55dc471,0x6fd40604,0xff155060,0x24fb9819,0x97e9bdd6,
+    0xcc434089,0x779ed967,0xbd42e8b0,0x888b8907,0x385b19e7,0xdbeec879,
+    0x470a7ca1,0xe90f427c,0xc91e84f8,0x0,0x83868009,0x48ed2b32,
+    0xac70111e,0x4e725a6c,0xfbff0efd,0x5638850f,0x1ed5ae3d,0x27392d36,
+    0x64d90f0a,0x21a65c68,0xd1545b9b,0x3a2e3624,0xb1670a0c,0xfe75793,
+    0xd296eeb4,0x9e919b1b,0x4fc5c080,0xa220dc61,0x694b775a,0x161a121c,
+    0xaba93e2,0xe52aa0c0,0x43e0223c,0x1d171b12,0xb0d090e,0xadc78bf2,
+    0xb9a8b62d,0xc8a91e14,0x8519f157,0x4c0775af,0xbbdd99ee,0xfd607fa3,
+    0x9f2601f7,0xbcf5725c,0xc53b6644,0x347efb5b,0x7629438b,0xdcc623cb,
+    0x68fcedb6,0x63f1e4b8,0xcadc31d7,0x10856342,0x40229713,0x2011c684,
+    0x7d244a85,0xf83dbbd2,0x1132f9ae,0x6da129c7,0x4b2f9e1d,0xf330b2dc,
+    0xec52860d,0xd0e3c177,0x6c16b32b,0x99b970a9,0xfa489411,0x2264e947,
+    0xc48cfca8,0x1a3ff0a0,0xd82c7d56,0xef903322,0xc74e4987,0xc1d138d9,
+    0xfea2ca8c,0x360bd498,0xcf81f5a6,0x28de7aa5,0x268eb7da,0xa4bfad3f,
+    0xe49d3a2c,0xd927850,0x9bcc5f6a,0x62467e54,0xc2138df6,0xe8b8d890,
+    0x5ef7392e,0xf5afc382,0xbe805d9f,0x7c93d069,0xa92dd56f,0xb31225cf,
+    0x3b99acc8,0xa77d1810,0x6e639ce8,0x7bbb3bdb,0x97826cd,0xf418596e,
+    0x1b79aec,0xa89a4f83,0x656e95e6,0x7ee6ffaa,0x8cfbc21,0xe6e815ef,
+    0xd99be7ba,0xce366f4a,0xd4099fea,0xd67cb029,0xafb2a431,0x31233f2a,
+    0x3094a5c6,0xc066a235,0x37bc4e74,0xa6ca82fc,0xb0d090e0,0x15d8a733,
+    0x4a9804f1,0xf7daec41,0xe50cd7f,0x2ff69117,0x8dd64d76,0x4db0ef43,
+    0x544daacc,0xdf0496e4,0xe3b5d19e,0x1b886a4c,0xb81f2cc1,0x7f516546,
+    0x4ea5e9d,0x5d358c01,0x737487fa,0x2e410bfb,0x5a1d67b3,0x52d2db92,
+    0x335610e9,0x1347d66d,0x8c61d79a,0x7a0ca137,0x8e14f859,0x893c13eb,
+    0xee27a9ce,0x35c961b7,0xede51ce1,0x3cb1477a,0x59dfd29c,0x3f73f255,
+    0x79ce1418,0xbf37c773,0xeacdf753,0x5baafd5f,0x146f3ddf,0x86db4478,
+    0x81f3afca,0x3ec468b9,0x2c342438,0x5f40a3c2,0x72c31d16,0xc25e2bc,
+    0x8b493c28,0x41950dff,0x7101a839,0xdeb30c08,0x9ce4b4d8,0x90c15664,
+    0x6184cb7b,0x70b632d5,0x745c6c48,0x4257b8d0}
+
+type AES struct {
+       Nk int
+       Nr int
+       mode int
+       fkey [60]uint32
+       rkey [60]uint32
+       f [16]byte
+}
+
+/* Rotates 32-bit word left by 1, 2 or 3 byte  */
+
+func aes_ROTL8(x uint32) uint32 {
+       return (((x)<<8)|((x)>>24))
+}
+
+func aes_ROTL16(x uint32) uint32 {
+       return (((x)<<16)|((x)>>16))
+}
+
+func aes_ROTL24(x uint32) uint32 {
+       return (((x)<<24)|((x)>>8))
+}
+
+func aes_pack(b [4]byte) uint32 { /* pack bytes into a 32-bit Word */
+        return 
((uint32(b[3])&0xff)<<24)|((uint32(b[2])&0xff)<<16)|((uint32(b[1])&0xff)<<8)|(uint32(b[0])&0xff)
+}
+  
+func aes_unpack(a uint32) [4]byte { /* unpack bytes from a word */
+        var 
b=[4]byte{byte(a&0xff),byte((a>>8)&0xff),byte((a>>16)&0xff),byte((a>>24)&0xff)}
+       return b;
+}
+  
+func aes_bmul(x byte,y byte) byte { /* x.y= AntiLog(Log(x) + Log(y)) */
+    
+        ix:=int(x)&0xff
+        iy:=int(y)&0xff
+        lx:=int(aes_ltab[ix])&0xff
+        ly:=int(aes_ltab[iy])&0xff
+    
+        if x != 0 && y != 0 {
+               return aes_ptab[(lx+ly)%255]
+       } else {return byte(0)}
+}
+  
+func aes_SubByte(a uint32) uint32 {
+        b:=aes_unpack(a)
+        b[0]=aes_fbsub[int(b[0])]
+        b[1]=aes_fbsub[int(b[1])]
+        b[2]=aes_fbsub[int(b[2])]
+        b[3]=aes_fbsub[int(b[3])]
+        return aes_pack(b);
+}    
+
+func aes_product(x uint32,y uint32) byte { /* dot product of two 4-byte arrays 
*/
+        xb:=aes_unpack(x)
+        yb:=aes_unpack(y)
+    
+        return 
(aes_bmul(xb[0],yb[0])^aes_bmul(xb[1],yb[1])^aes_bmul(xb[2],yb[2])^aes_bmul(xb[3],yb[3]))
+}
+
+func aes_InvMixCol(x uint32) uint32 { /* matrix Multiplication */
+        var b [4]byte
+        m:=aes_pack(aes_InCo)
+        b[3]=aes_product(m,x)
+        m=aes_ROTL24(m)
+        b[2]=aes_product(m,x)
+        m=aes_ROTL24(m)
+        b[1]=aes_product(m,x)
+        m=aes_ROTL24(m)
+        b[0]=aes_product(m,x)
+        var y=aes_pack(b)
+        return y
+}
+
+func aes_increment(f []byte) {
+       for i:=0;i<16;i++ {
+               f[i]++
+               if f[i]!=0 {break}
+       }
+}
+
+/* reset cipher */
+func (A *AES) Reset(m int,iv []byte) { /* reset mode, or reset iv */
+       A.mode=m;
+        for i:=0;i<16;i++ {A.f[i]=0}
+        if (A.mode != aes_ECB) && (iv != nil) {
+            for i:=0;i<16;i++ {A.f[i]=iv[i]}
+       }
+}
+
+func (A *AES) Init(m int,nk int,key []byte,iv []byte) bool { 
+/* Key Scheduler. Create expanded encryption key */
+       var CipherKey [8]uint32
+        var b [4]byte
+        nk/=4
+       if nk!=4 && nk!=6 && nk!=8 {return false}
+       nr:=6+nk
+       A.Nk=nk
+       A.Nr=nr
+        A.Reset(m,iv);
+        N:=4*(nr+1)
+        
+        j:=0
+        for  i:=0;i<nk;i++ {
+            for k:=0;k<4;k++ {b[k]=key[j+k]}
+            CipherKey[i]=aes_pack(b);
+            j+=4;
+        }
+        for i:=0;i<nk;i++ {A.fkey[i]=CipherKey[i]}
+        j=nk
+        for k:=0;j<N;k++ {
+            
A.fkey[j]=A.fkey[j-nk]^aes_SubByte(aes_ROTL24(A.fkey[j-1]))^uint32(aes_rco[k])
+            for i:=1;i<nk && (i+j)<N;i++ {
+                A.fkey[i+j]=A.fkey[i+j-nk]^A.fkey[i+j-1]
+            }
+            j+=nk
+        }
+        
+        /* now for the expanded decrypt key in reverse order */
+        
+        for j:=0;j<4;j++ {A.rkey[j+N-4]=A.fkey[j]}
+        for i:=4;i<N-4;i+=4 {
+            k:=N-4-i;
+            for j:=0;j<4;j++ {A.rkey[k+j]=aes_InvMixCol(A.fkey[i+j])}
+        }
+        for j:=N-4;j<N;j++ {A.rkey[j-N+4]=A.fkey[j]}
+       return true
+}
+
+func NewAES() *AES {
+       var A=new(AES)
+       return A
+}
+
+func (A *AES) Getreg() [16]byte {
+        var ir [16]byte
+        for i:=0;i<16;i++ {ir[i]=A.f[i]}
+        return ir
+}
+
+    /* Encrypt a single block */
+func (A *AES) ecb_encrypt(buff []byte) {
+        var b [4]byte
+        var p [4]uint32
+        var q [4]uint32
+    
+        j:=0
+        for i:=0;i<4;i++ {
+            for k:=0;k<4;k++ {b[k]=buff[j+k]}
+            p[i]=aes_pack(b)
+            p[i]^=A.fkey[i]
+            j+=4
+        }
+    
+        k:=4
+    
+    /* State alternates between p and q */
+        for i:=1;i<A.Nr;i++ {
+            
q[0]=A.fkey[k]^aes_ftable[int(p[0]&0xff)]^aes_ROTL8(aes_ftable[int((p[1]>>8)&0xff)])^aes_ROTL16(aes_ftable[int((p[2]>>16)&0xff)])^aes_ROTL24(aes_ftable[int((p[3]>>24)&0xff)])
+            
+            
q[1]=A.fkey[k+1]^aes_ftable[int(p[1]&0xff)]^aes_ROTL8(aes_ftable[int((p[2]>>8)&0xff)])^aes_ROTL16(aes_ftable[int((p[3]>>16)&0xff)])^aes_ROTL24(aes_ftable[int((p[0]>>24)&0xff)])
+            
+            
q[2]=A.fkey[k+2]^aes_ftable[int(p[2]&0xff)]^aes_ROTL8(aes_ftable[int((p[3]>>8)&0xff)])^aes_ROTL16(aes_ftable[int((p[0]>>16)&0xff)])^aes_ROTL24(aes_ftable[int((p[1]>>24)&0xff)])
+            
+            
q[3]=A.fkey[k+3]^aes_ftable[int(p[3]&0xff)]^aes_ROTL8(aes_ftable[int((p[0]>>8)&0xff)])^aes_ROTL16(aes_ftable[int((p[1]>>16)&0xff)])^aes_ROTL24(aes_ftable[int((p[2]>>24)&0xff)])
+            
+            k+=4;
+            for j=0;j<4;j++ {
+               t:=p[j]; p[j]=q[j]; q[j]=t
+            }
+        }
+    
+    /* Last Round */
+    
+        
q[0]=A.fkey[k]^uint32(aes_fbsub[int(p[0]&0xff)])^aes_ROTL8(uint32(aes_fbsub[int((p[1]>>8)&0xff)]))^aes_ROTL16(uint32(aes_fbsub[int((p[2]>>16)&0xff)]))^aes_ROTL24(uint32(aes_fbsub[int((p[3]>>24)&0xff)]))
+    
+        
q[1]=A.fkey[k+1]^uint32(aes_fbsub[int(p[1]&0xff)])^aes_ROTL8(uint32(aes_fbsub[int((p[2]>>8)&0xff)]))^aes_ROTL16(uint32(aes_fbsub[int((p[3]>>16)&0xff)]))^aes_ROTL24(uint32(aes_fbsub[int((p[0]>>24)&0xff)]))
+    
+        
q[2]=A.fkey[k+2]^uint32(aes_fbsub[int(p[2]&0xff)])^aes_ROTL8(uint32(aes_fbsub[int((p[3]>>8)&0xff)]))^aes_ROTL16(uint32(aes_fbsub[int((p[0]>>16)&0xff)]))^aes_ROTL24(uint32(aes_fbsub[int((p[1]>>24)&0xff)]))
+    
+        
q[3]=A.fkey[k+3]^uint32(aes_fbsub[int(p[3]&0xff)])^aes_ROTL8(uint32(aes_fbsub[int((p[0]>>8)&0xff)]))^aes_ROTL16(uint32(aes_fbsub[int((p[1]>>16)&0xff)]))^aes_ROTL24(uint32(aes_fbsub[int((p[2]>>24)&0xff)]))
+    
+        j=0
+        for i:=0;i<4;i++ {
+            b=aes_unpack(q[i])
+            for k=0;k<4;k++ {buff[j+k]=b[k]}
+            j+=4
+        }
+}
+    
+    /* Decrypt a single block */
+func (A *AES)  ecb_decrypt(buff []byte) {
+        var b [4]byte
+        var p [4]uint32
+        var q [4]uint32
+    
+        j:=0
+        for i:=0;i<4;i++ {
+            for k:=0;k<4;k++ {b[k]=buff[j+k]}
+            p[i]=aes_pack(b)
+            p[i]^=A.rkey[i]
+            j+=4
+        }
+    
+        k:=4
+    
+    /* State alternates between p and q */
+        for i:=1;i<A.Nr;i++ {
+            
+            
q[0]=A.rkey[k]^aes_rtable[int(p[0]&0xff)]^aes_ROTL8(aes_rtable[int((p[3]>>8)&0xff)])^aes_ROTL16(aes_rtable[int((p[2]>>16)&0xff)])^aes_ROTL24(aes_rtable[int((p[1]>>24)&0xff)])
+            
+            
q[1]=A.rkey[k+1]^aes_rtable[int(p[1]&0xff)]^aes_ROTL8(aes_rtable[int((p[0]>>8)&0xff)])^aes_ROTL16(aes_rtable[int((p[3]>>16)&0xff)])^aes_ROTL24(aes_rtable[int((p[2]>>24)&0xff)])
+            
+        
+            
q[2]=A.rkey[k+2]^aes_rtable[int(p[2]&0xff)]^aes_ROTL8(aes_rtable[int((p[1]>>8)&0xff)])^aes_ROTL16(aes_rtable[int((p[0]>>16)&0xff)])^aes_ROTL24(aes_rtable[int((p[3]>>24)&0xff)])
+       
+            
q[3]=A.rkey[k+3]^aes_rtable[int(p[3]&0xff)]^aes_ROTL8(aes_rtable[int((p[2]>>8)&0xff)])^aes_ROTL16(aes_rtable[int((p[1]>>16)&0xff)])^aes_ROTL24(aes_rtable[int((p[0]>>24)&0xff)])
+            
+    
+            k+=4;
+            for j:=0;j<4;j++ {
+                       t:=p[j]; p[j]=q[j]; q[j]=t
+            }
+        }
+    
+    /* Last Round */
+        
+        
q[0]=A.rkey[k]^uint32(aes_rbsub[int(p[0]&0xff)])^aes_ROTL8(uint32(aes_rbsub[int((p[3]>>8)&0xff)]))^aes_ROTL16(uint32(aes_rbsub[int((p[2]>>16)&0xff)]))^aes_ROTL24(uint32(aes_rbsub[int((p[1]>>24)&0xff)]))
+        
+        
q[1]=A.rkey[k+1]^uint32(aes_rbsub[int(p[1]&0xff)])^aes_ROTL8(uint32(aes_rbsub[int((p[0]>>8)&0xff)]))^aes_ROTL16(uint32(aes_rbsub[int((p[3]>>16)&0xff)]))^aes_ROTL24(uint32(aes_rbsub[int((p[2]>>24)&0xff)]))
+        
+        
+        
q[2]=A.rkey[k+2]^uint32(aes_rbsub[int(p[2]&0xff)])^aes_ROTL8(uint32(aes_rbsub[int((p[1]>>8)&0xff)]))^aes_ROTL16(uint32(aes_rbsub[int((p[0]>>16)&0xff)]))^aes_ROTL24(uint32(aes_rbsub[int((p[3]>>24)&0xff)]))
+
+        
q[3]=A.rkey[k+3]^uint32(aes_rbsub[int((p[3])&0xff)])^aes_ROTL8(uint32(aes_rbsub[int((p[2]>>8)&0xff)]))^aes_ROTL16(uint32(aes_rbsub[int((p[1]>>16)&0xff)]))^aes_ROTL24(uint32(aes_rbsub[int((p[0]>>24)&0xff)]))
+    
+        j=0
+        for i:=0;i<4;i++ {
+            b=aes_unpack(q[i]);
+            for k:=0;k<4;k++ {buff[j+k]=b[k]}
+            j+=4
+        }
+}
+
+/* Encrypt using selected mode of operation */
+func (A *AES) Encrypt(buff []byte) uint32 {
+       var st [16]byte
+    
+    // Supported Modes of Operation
+    
+        var fell_off uint32=0
+        switch A.mode {
+        case aes_ECB:
+            A.ecb_encrypt(buff)
+            return 0
+        case aes_CBC:
+            for j:=0;j<16;j++ {buff[j]^=A.f[j]}
+            A.ecb_encrypt(buff)
+            for j:=0;j<16;j++ {A.f[j]=buff[j]}
+            return 0
+    
+        case aes_CFB1:
+            fallthrough
+        case aes_CFB2:
+            fallthrough
+        case aes_CFB4:
+            bytes:=A.mode-aes_CFB1+1
+            for j:=0;j<bytes;j++ {fell_off=(fell_off<<8)|uint32(A.f[j])}
+            for j:=0;j<16;j++ {st[j]=A.f[j]}
+            for j:=bytes;j<16;j++ {A.f[j-bytes]=A.f[j]}
+            A.ecb_encrypt(st[:])
+            for j:=0;j<bytes;j++ {
+               buff[j]^=st[j]
+               A.f[16-bytes+j]=buff[j]
+            }
+            return fell_off
+    
+        case aes_OFB1:
+            fallthrough
+        case aes_OFB2:
+            fallthrough
+        case aes_OFB4:
+            fallthrough
+        case aes_OFB8:
+            fallthrough
+        case aes_OFB16:
+    
+            bytes:=A.mode-aes_OFB1+1
+            A.ecb_encrypt(A.f[:])
+            for j:=0;j<bytes;j++ {buff[j]^=A.f[j]}
+            return 0;
+    
+       case aes_CTR1:
+           fallthrough
+       case aes_CTR2:
+           fallthrough
+       case aes_CTR4:
+           fallthrough
+       case aes_CTR8:
+           fallthrough
+       case aes_CTR16:
+           bytes:=A.mode-aes_CTR1+1
+           for j:=0;j<16;j++ {st[j]=A.f[j]}
+           A.ecb_encrypt(st[:])
+           for j:=0;j<bytes;j++ {buff[j]^=st[j]}
+           aes_increment(A.f[:])
+           return 0
+
+        default:
+            return 0
+        }
+}
+    
+    /* Decrypt using selected mode of operation */
+func (A *AES) Decrypt(buff []byte) uint32 {
+
+       var st [16]byte
+        
+        // Supported Modes of Operation
+        
+        var fell_off uint32=0
+        switch A.mode {
+        case aes_ECB:
+            A.ecb_decrypt(buff);
+            return 0;
+        case aes_CBC:
+            for j:=0;j<16;j++ {
+               st[j]=A.f[j];
+               A.f[j]=buff[j];
+            }
+            A.ecb_decrypt(buff);
+            for j:=0;j<16;j++ {
+               buff[j]^=st[j];
+               st[j]=0
+            }
+            return 0
+        case aes_CFB1:
+            fallthrough
+        case aes_CFB2:
+            fallthrough
+        case aes_CFB4:
+            bytes:=A.mode-aes_CFB1+1;
+            for j:=0;j<bytes;j++ {fell_off=(fell_off<<8)|uint32(A.f[j])}
+            for j:=0;j<16;j++ {st[j]=A.f[j]}
+            for j:=bytes;j<16;j++ {A.f[j-bytes]=A.f[j]}
+            A.ecb_encrypt(st[:])
+            for j:=0;j<bytes;j++ {
+               A.f[16-bytes+j]=buff[j]
+               buff[j]^=st[j]
+            }
+            return fell_off
+        case aes_OFB1:
+            fallthrough
+        case aes_OFB2:
+            fallthrough
+        case aes_OFB4:
+            fallthrough
+        case aes_OFB8:
+            fallthrough
+        case aes_OFB16:
+            bytes:=A.mode-aes_OFB1+1
+            A.ecb_encrypt(A.f[:]);
+            for j:=0;j<bytes;j++ {buff[j]^=A.f[j]}
+            return 0
+
+       case aes_CTR1:
+           fallthrough
+       case aes_CTR2:
+           fallthrough
+       case aes_CTR4:
+           fallthrough
+       case aes_CTR8:
+           fallthrough
+       case aes_CTR16:
+           bytes:=A.mode-aes_CTR1+1
+           for j:=0;j<16;j++ {st[j]=A.f[j]}
+           A.ecb_encrypt(st[:])
+           for j:=0;j<bytes;j++ {buff[j]^=st[j]}
+           aes_increment(A.f[:])
+           return 0
+
+        default:
+            return 0;
+        }
+    } 
+    
+/* Clean up and delete left-overs */
+func (A *AES) End() { // clean up
+    for i:=0;i<4*(A.Nr+1);i++ {A.fkey[i]=0; A.rkey[i]=0}
+    for i:=0;i<16;i++ {A.f[i]=0}
+}
+/*
+func main() {
+       var key [32]byte
+       var block [16]byte
+       var iv [16]byte
+
+       for i:=0;i<32;i++ {key[i]=0}
+       key[0]=1
+       for i:=0;i<16;i++ {iv[i]=byte(i)}
+       for i:=0;i<16;i++ {block[i]=byte(i)}
+
+       a:=NewAES()
+
+       a.Init(aes_CTR16,32,key[:],iv[:])
+       fmt.Printf("Plain= \n")
+       for i:=0;i<16;i++  {fmt.Printf("%02X ", block[i]&0xff)}
+       fmt.Printf("\n")
+
+       a.Encrypt(block[:])
+
+       fmt.Printf("Encrypt= \n") 
+       for i:=0;i<16;i++  {fmt.Printf("%02X ", block[i]&0xff)}
+       fmt.Printf("\n")
+
+       a.Reset(aes_CTR16,iv[:])
+       a.Decrypt(block[:])
+
+       fmt.Printf("Decrypt= \n") 
+       for i:=0;i<16;i++  {fmt.Printf("%02X ", block[i]&0xff)}
+       fmt.Printf("\n")
+
+       a.End();
+}
+*/

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/go/BIG.go
----------------------------------------------------------------------
diff --git a/version22/go/BIG.go b/version22/go/BIG.go
new file mode 100644
index 0000000..3e0eca5
--- /dev/null
+++ b/version22/go/BIG.go
@@ -0,0 +1,850 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* AMCL BIG number class */ 
+
+package main
+
+import "strconv"
+//import "fmt"
+
+
+type BIG struct {
+       w [NLEN]Chunk
+}
+
+type DBIG struct {
+       w [2*NLEN]Chunk
+}
+
+func (r *BIG) get(i int) Chunk {
+       return r.w[i] 
+}
+
+func (r *BIG) set(i int,x Chunk) {
+       r.w[i]=x        
+}
+
+func (r *BIG) xortop(x Chunk) {
+       r.w[NLEN-1]^=x
+}
+
+/* calculate Field Excess */
+func EXCESS(a *BIG) Chunk {
+       return ((a.w[NLEN-1]&OMASK)>>(MODBITS%BASEBITS))
+}
+
+func FF_EXCESS(a* BIG) Chunk {
+       return ((a.w[NLEN-1]&P_OMASK)>>(P_MB))
+}
+
+/* normalise BIG - force all digits < 2^BASEBITS */
+func (r *BIG) norm() Chunk {
+       carry:=Chunk(0)
+       for i:=0;i<NLEN-1;i++ {
+               d:=r.w[i]+carry
+               r.w[i]=d&BMASK
+               carry=d>>BASEBITS
+       }
+       r.w[NLEN-1]=(r.w[NLEN-1]+carry)
+       return (r.w[NLEN-1]>>((8*MODBYTES)%BASEBITS))  
+}
+
+/* Shift right by less than a word */
+func (r *BIG) fshr(k uint) int {
+       w:=r.w[0]&((Chunk(1)<<k)-1) /* shifted out part */
+       for i:=0;i<NLEN-1;i++ {
+               r.w[i]=(r.w[i]>>k)|((r.w[i+1]<<(BASEBITS-k))&BMASK)
+       }
+       r.w[NLEN-1]=r.w[NLEN-1]>>k
+       return int(w)
+}
+
+/* Shift right by less than a word */
+func (r *BIG) fshl(k uint) int {
+       r.w[NLEN-1]=((r.w[NLEN-1]<<k))|(r.w[NLEN-2]>>(BASEBITS-k))
+       for i:=NLEN-2;i>0;i-- {
+               r.w[i]=((r.w[i]<<k)&BMASK)|(r.w[i-1]>>(BASEBITS-k))
+       }
+       r.w[0]=(r.w[0]<<k)&BMASK
+       return int(r.w[NLEN-1]>>((8*MODBYTES)%BASEBITS)) /* return excess - 
only used in ff.c */
+}
+
+func NewBIG() *BIG {
+       b:=new(BIG)
+       for i:=0;i<NLEN;i++ {
+               b.w[i]=0
+       }
+       return b
+}
+
+func NewBIGints(x [NLEN]Chunk) *BIG {
+       b:=new(BIG)
+       for i:=0;i<NLEN;i++ {
+               b.w[i]=x[i]
+       }
+       return b        
+}
+
+func NewBIGint(x int) *BIG {
+       b:=new(BIG)
+       b.w[0]=Chunk(x)
+       for i:=1;i<NLEN;i++ {
+               b.w[i]=0
+       }
+       return b
+}
+
+func NewBIGcopy(x *BIG) *BIG {
+       b:=new(BIG)
+       for i:=0;i<NLEN;i++ {
+               b.w[i]=x.w[i]
+       }
+       return b
+}
+
+func NewBIGdcopy(x *DBIG) *BIG {
+       b:=new(BIG)
+       for i:=0;i<NLEN;i++ {
+               b.w[i]=x.w[i]
+       }
+       return b
+}
+
+/* test for zero */
+func (r *BIG) iszilch() bool {
+       for i:=0;i<NLEN;i++ {
+               if r.w[i]!=0 {return false}
+       }
+       return true; 
+}
+
+/* set to zero */
+func (r *BIG) zero() {
+       for i:=0;i<NLEN;i++ {
+               r.w[i]=0
+       }
+}
+
+/* Test for equal to one */
+func (r *BIG) isunity() bool {
+       for i:=1;i<NLEN;i++ {
+               if r.w[i]!=0 {return false}
+       }
+       if r.w[0]!=1 {return false}
+       return true;
+}
+
+
+/* set to one */
+func (r *BIG) one() {
+       r.w[0]=1
+       for i:=1;i<NLEN;i++ {
+               r.w[i]=0
+       }
+}
+
+/* Copy from another BIG */
+func (r *BIG) copy(x *BIG) {
+       for i:=0;i<NLEN;i++ {
+               r.w[i]=x.w[i]
+       }
+}
+
+/* Copy from another DBIG */
+func (r *BIG) dcopy(x *DBIG) {
+       for i:=0;i<NLEN;i++ {
+               r.w[i]=x.w[i]
+       }
+}
+
+/* Conditional swap of two bigs depending on d using XOR - no branches */
+func (r *BIG) cswap(b *BIG,d int) {
+       c:=Chunk(d)
+       c=^(c-1)
+
+       for i:=0;i<NLEN;i++ {
+               t:=c&(r.w[i]^b.w[i])
+               r.w[i]^=t
+               b.w[i]^=t
+       }
+}
+
+func (r *BIG) cmove(g *BIG,d int){
+       b:=Chunk(-d)
+
+       for i:=0;i<NLEN;i++ {
+               r.w[i]^=(r.w[i]^g.w[i])&b
+       }
+}
+
+/* general shift right */
+func (r *BIG) shr(k uint) {
+       n:=(k%BASEBITS)
+       m:=int(k/BASEBITS)      
+       for i:=0;i<NLEN-m-1;i++ {
+               r.w[i]=(r.w[m+i]>>n)|((r.w[m+i+1]<<(BASEBITS-n))&BMASK)
+       }
+       r.w[NLEN-m-1]=r.w[NLEN-1]>>n;
+       for i:=NLEN-m;i<NLEN;i++ {r.w[i]=0}
+}
+
+
+/* general shift left */
+func (r *BIG) shl(k uint) {
+       n:=k%BASEBITS
+       m:=int(k/BASEBITS)
+
+       r.w[NLEN-1]=((r.w[NLEN-1-m]<<n))
+       if NLEN>=m+2 {r.w[NLEN-1]|=(r.w[NLEN-m-2]>>(BASEBITS-n))}
+       for i:=NLEN-2;i>m;i-- {
+               r.w[i]=((r.w[i-m]<<n)&BMASK)|(r.w[i-m-1]>>(BASEBITS-n))
+       }
+       r.w[m]=(r.w[0]<<n)&BMASK; 
+       for i:=0;i<m;i++ {r.w[i]=0}
+}
+
+/* return number of bits */
+func (r *BIG) nbits() int {
+       k:=NLEN-1
+       r.norm()
+       for (k>=0 && r.w[k]==0) {k--}
+       if k<0 {return 0}
+       bts:=int(BASEBITS)*k;
+       c:=r.w[k];
+       for c!=0 {c/=2; bts++}
+       return bts
+}
+
+/* Convert to Hex String */
+func (r *BIG) toString() string {
+       s:=""
+       len:=r.nbits()
+
+       if len%4==0 {
+               len/=4
+       } else {
+               len/=4 
+               len++
+
+       }
+       MB:=int(MODBYTES*2)
+       if len<MB {len=MB}
+
+       for i:=len-1;i>=0;i-- {
+               b:=NewBIGcopy(r)
+               
+               b.shr(uint(i*4))
+               s+=strconv.FormatInt(int64(b.w[0]&15),16)
+       }
+       return s
+}
+
+func (r *BIG) add(x *BIG) {
+       for i:=0;i<NLEN;i++ {
+               r.w[i]=r.w[i]+x.w[i] 
+       }
+}
+
+/* return this+x */
+func (r *BIG) plus(x *BIG) *BIG {
+       s:=new(BIG)
+       for i:=0;i<NLEN;i++ {
+               s.w[i]=r.w[i]+x.w[i];
+       }
+       return s;
+}
+
+/* this+=x, where x is int */
+func (r *BIG) inc(x int) {
+       r.norm();
+       r.w[0]+=Chunk(x);
+}
+
+/* this*=c and catch overflow in DBIG */
+func (r *BIG) pxmul(c int) *DBIG {
+       m:=NewDBIG()    
+       carry:=Chunk(0)
+       for j:=0;j<NLEN;j++ {
+               carry,m.w[j]=muladd(r.w[j],Chunk(c),carry,m.w[j])
+       }
+       m.w[NLEN]=carry;                
+       return m;
+}
+
+/* return this-x */
+func (r *BIG) minus(x *BIG) *BIG {
+       d:=new(BIG)
+       for i:=0;i<NLEN;i++ {
+               d.w[i]=r.w[i]-x.w[i] 
+       }
+       return d;
+}
+
+/* this-=x */
+func (r *BIG) sub(x *BIG) {
+       for i:=0;i<NLEN;i++ {
+               r.w[i]=r.w[i]-x.w[i] 
+       }
+} 
+
+/* reverse subtract this=x-this */ 
+func (r *BIG) rsub(x *BIG) {
+       for i:=0;i<NLEN;i++ {
+               r.w[i]=x.w[i]-r.w[i] 
+       }
+} 
+
+/* this-=x, where x is int */
+func (r *BIG) dec(x int) {
+       r.norm();
+       r.w[0]-=Chunk(x)
+} 
+
+/* this*=x, where x is small int<NEXCESS */
+func (r *BIG) imul(c int) {
+       for i:=0;i<NLEN;i++{ 
+               r.w[i]*=Chunk(c)
+       }
+}
+
+/* this*=x, where x is >NEXCESS */
+func (r *BIG) pmul(c int) Chunk {
+       carry:=Chunk(0)
+       r.norm();
+       for i:=0;i<NLEN;i++ {
+               ak:=r.w[i]
+               r.w[i]=0
+               carry,r.w[i]=muladd(ak,Chunk(c),carry,r.w[i])
+       }
+       return carry
+}
+
+/* convert this BIG to byte array */
+func (r *BIG) tobytearray(b []byte,n int) {
+       r.norm();
+       c:=NewBIGcopy(r)
+
+       for i:=int(MODBYTES)-1;i>=0;i-- {
+               b[i+n]=byte(c.w[0])
+               c.fshr(8)
+       }
+}
+
+/* convert from byte array to BIG */
+func frombytearray(b []byte,n int) *BIG {
+       m:=NewBIG();
+       for i:=0;i<int(MODBYTES);i++ {
+               m.fshl(8); m.w[0]+=Chunk(int(b[i+n]&0xff))
+       }
+       return m
+}
+
+func (r *BIG) toBytes(b []byte) {
+       r.tobytearray(b,0)
+}
+
+func fromBytes(b []byte) *BIG {
+       return frombytearray(b,0)
+}
+
+/* divide by 3 */
+func (r *BIG) div3() int {     
+       carry:=Chunk(0)
+       r.norm();
+       base:=(Chunk(1)<<BASEBITS)
+       for i:=NLEN-1;i>=0;i-- {
+               ak:=(carry*base+r.w[i])
+               r.w[i]=ak/3;
+               carry=ak%3;
+       }
+       return int(carry)
+}
+
+/* return a*b where result fits in a BIG */
+func smul(a *BIG,b *BIG) *BIG {
+       carry:=Chunk(0)
+       c:=NewBIG()
+       for i:=0;i<NLEN;i++ {
+               carry=0;
+               for j:=0;j<NLEN;j++ {
+                       if i+j<NLEN {
+                               
carry,c.w[i+j]=muladd(a.w[i],b.w[j],carry,c.w[i+j])
+                               //carry=c.muladd(a.w[i],b.w[j],carry,i+j)
+                       }
+               }
+       }
+       return c;
+}
+
+/* reduce a DBIG to a BIG using the appropriate form of the modulus */
+func mod(d *DBIG) *BIG {
+       if MODTYPE==PSEUDO_MERSENNE {
+               t:=d.split(MODBITS)
+               b:=NewBIGdcopy(d)
+
+               v:=t.pmul(int(MConst))
+               tw:=t.w[NLEN-1]
+               t.w[NLEN-1]&=TMASK
+               t.w[0]+=(MConst*((tw>>TBITS)+(v<<(BASEBITS-TBITS))))
+
+               b.add(t)
+               b.norm()
+               return b                
+       }
+       if MODTYPE==MONTGOMERY_FRIENDLY {
+               for i:=0;i<NLEN;i++ {
+                       top,bot:=muladd(d.w[i],MConst-1,d.w[i],d.w[NLEN+i-1])
+                       d.w[NLEN+i-1]=bot
+                       d.w[NLEN+i]+=top
+                       //d.w[NLEN+i]+=d.muladd(d.w[i],MConst-1,d.w[i],NLEN+i-1)
+               }
+               b:=NewBIG()
+
+               for i:=0;i<NLEN;i++ {
+                       b.w[i]=d.w[NLEN+i]
+               }
+               b.norm()
+               return b                
+       }
+
+       if MODTYPE==GENERALISED_MERSENNE { // GoldiLocks only
+               t:=d.split(MODBITS)
+               b:=NewBIGdcopy(d)
+               b.add(t);
+               dd:=NewDBIGscopy(t)
+               dd.shl(MODBITS/2)
+
+               tt:=dd.split(MODBITS)
+               lo:=NewBIGdcopy(dd)
+               b.add(tt)
+               b.add(lo)
+               b.norm()
+               tt.shl(MODBITS/2)
+               b.add(tt)
+
+               carry:=b.w[NLEN-1]>>TBITS
+               b.w[NLEN-1]&=TMASK
+               b.w[0]+=carry
+                       
+               b.w[224/BASEBITS]+=carry<<(224%BASEBITS);
+               b.norm()
+               return b                
+       }
+
+       if MODTYPE==NOT_SPECIAL {
+               md:=NewBIGints(Modulus)
+               return monty(md,MConst,d) 
+       }
+       return NewBIG()
+}
+
+/* Compare a and b, return 0 if a==b, -1 if a<b, +1 if a>b. Inputs must be 
normalised */
+func comp(a *BIG,b *BIG) int {
+       for i:=NLEN-1;i>=0;i-- {
+               if a.w[i]==b.w[i] {continue}
+               if a.w[i]>b.w[i] {
+                       return 1
+               } else  {return -1}
+       }
+       return 0
+}
+
+/* return parity */
+func (r *BIG) parity() int {
+       return int(r.w[0]%2)
+}
+
+/* return n-th bit */
+func (r *BIG) bit(n int) int {
+       if (r.w[n/int(BASEBITS)]&(Chunk(1)<<(uint(n)%BASEBITS)))>0 {return 1}
+       return 0;
+}
+
+/* return n last bits */
+func (r *BIG) lastbits(n int) int {
+       msk:=(1<<uint(n))-1;
+       r.norm();
+       return (int(r.w[0]))&msk
+}
+
+
+/* set x = x mod 2^m */
+func (r *BIG) mod2m(m uint) {
+       wd:=int(m/BASEBITS)
+       bt:=m%BASEBITS
+       msk:=(Chunk(1)<<bt)-1
+       r.w[wd]&=msk
+       for i:=wd+1;i<NLEN;i++ {r.w[i]=0}
+}
+
+/* Arazi and Qi inversion mod 256 */
+func invmod256(a int) int {
+       var t1 int=0
+       c:=(a>>1)&1
+       t1+=c
+       t1&=1
+       t1=2-t1
+       t1<<=1
+       U:=t1+1;
+
+// i=2
+       b:=a&3;
+       t1=U*b; t1>>=2
+       c=(a>>2)&3
+       t2:=(U*c)&3
+       t1+=t2;
+       t1*=U; t1&=3
+       t1=4-t1
+       t1<<=2
+       U+=t1
+
+// i=4
+       b=a&15
+       t1=U*b; t1>>=4
+       c=(a>>4)&15
+       t2=(U*c)&15
+       t1+=t2
+       t1*=U; t1&=15
+       t1=16-t1
+       t1<<=4
+       U+=t1
+
+       return U;
+}
+
+/* a=1/a mod 2^256. This is very fast! */
+func (r *BIG) invmod2m() {
+       U:=NewBIG()
+       b:=NewBIG()
+       c:=NewBIG()
+
+       U.inc(invmod256(r.lastbits(8)))
+
+       for i:=8;i<BIGBITS;i<<=1 {
+               ui:=uint(i);
+               b.copy(r); b.mod2m(ui)
+               t1:=smul(U,b); t1.shr(ui)
+               c.copy(r); c.shr(ui); c.mod2m(ui)
+
+               t2:=smul(U,c); t2.mod2m(ui)
+               t1.add(t2)
+               b=smul(t1,U); t1.copy(b)
+               t1.mod2m(ui);
+
+               t2.one(); t2.shl(ui); t1.rsub(t2); t1.norm()
+               t1.shl(ui);
+               U.add(t1);
+       }
+       U.mod2m(8*MODBYTES)
+       r.copy(U)
+       r.norm()
+}
+
+/* reduce this mod m */
+func (r *BIG) mod(m *BIG) {
+       sr:=NewBIG()
+       r.norm()
+       if comp(r,m)<0 {return}
+
+       m.fshl(1); k:=1
+
+       for comp(r,m)>=0 {
+               m.fshl(1)
+               k++;
+       }
+
+       for k>0 {
+               m.fshr(1);
+
+                       sr.copy(r)
+                       sr.sub(m)
+                       sr.norm()
+                       r.cmove(sr,int(1-((sr.w[NLEN-1]>>uint(CHUNK-1))&1)));
+/*
+               if comp(r,m)>=0 {
+                       r.sub(m)
+                       r.norm()
+               } */
+               k--;
+       }
+}
+
+/* divide this by m */
+func (r *BIG) div(m *BIG) {
+       var d int
+       k:=0
+       r.norm();
+       sr:=NewBIG();
+       e:=NewBIGint(1)
+       b:=NewBIGcopy(r)
+       r.zero();
+
+       for (comp(b,m)>=0) {
+               e.fshl(1)
+               m.fshl(1)
+               k++
+       }
+
+       for k>0 {
+               m.fshr(1)
+               e.fshr(1)
+
+               sr.copy(b);
+               sr.sub(m);
+               sr.norm();
+               d=int(1-((sr.w[NLEN-1]>>uint(CHUNK-1))&1));
+               b.cmove(sr,d);
+               sr.copy(r);
+               sr.add(e);
+               sr.norm();
+               r.cmove(sr,d);
+/*
+               if comp(b,m)>=0 {
+                       r.add(e)
+                       r.norm()
+                       b.sub(m)
+                       b.norm()
+               } */
+               k--
+       }
+}
+
+/* get 8*MODBYTES size random number */
+func random(rng *RAND) *BIG {
+       m:=NewBIG()
+       var j int=0
+       var r byte=0
+/* generate random BIG */ 
+       for i:=0;i<8*int(MODBYTES);i++   {
+               if j==0 {
+                       r=rng.GetByte()
+               } else {r>>=1}
+
+               b:=Chunk(int(r&1))
+               m.shl(1); m.w[0]+=b// m.inc(b)
+               j++; j&=7; 
+       }
+       return m;
+}
+
+/* Create random BIG in portable way, one bit at a time */
+func randomnum(q *BIG,rng *RAND) *BIG {
+       d:=NewDBIG();
+       var j int=0
+       var r byte=0
+       for i:=0;i<2*int(MODBITS);i++ {
+               if (j==0) {
+                       r=rng.GetByte();
+               } else {r>>=1}
+
+               b:=Chunk(int(r&1))
+               d.shl(1); d.w[0]+=b// m.inc(b);
+               j++; j&=7 
+       }
+       m:=d.mod(q)
+       return m;
+}
+
+
+/* return NAF value as +/- 1, 3 or 5. x and x3 should be normed. 
+nbs is number of bits processed, and nzs is number of trailing 0s detected */
+/*
+func nafbits(x *BIG,x3 *BIG ,i int) [3]int {
+       var n [3]int
+       var j int
+       nb:=x3.bit(i)-x.bit(i)
+
+
+       n[1]=1
+       n[0]=0
+       if nb==0 {n[0]=0; return n}
+       if i==0 {n[0]=nb; return n}
+       if nb>0 {
+               n[0]=1;
+       } else  {n[0]=(-1)}
+
+       for j=i-1;j>0;j-- {
+               n[1]++
+               n[0]*=2
+               nb=x3.bit(j)-x.bit(j)
+               if nb>0 {n[0]+=1}
+               if nb<0 {n[0]-=1}
+               if (n[0]>5 || n[0] < -5) {break}
+       }
+
+       if n[0]%2!=0 && j!=0 { // backtrack 
+               if nb>0 {n[0]=(n[0]-1)/2}
+               if nb<0 {n[0]=(n[0]+1)/2}
+               n[1]--
+       }
+       for n[0]%2==0 { // remove trailing zeros 
+               n[0]/=2
+               n[2]++
+               n[1]--
+       }
+       return n;
+}
+*/
+
+/* return a*b mod m */
+func modmul(a,b,m *BIG) *BIG {
+       a.mod(m)
+       b.mod(m)
+       d:=mul(a,b);
+       return d.mod(m)
+}
+
+/* return a^2 mod m */
+func modsqr(a,m *BIG) *BIG {
+       a.mod(m)
+       d:=sqr(a)
+       return d.mod(m)
+}
+
+/* return -a mod m */
+func modneg(a,m *BIG) *BIG {
+       a.mod(m)
+       return m.minus(a)
+}
+
+/* Jacobi Symbol (this/p). Returns 0, 1 or -1 */
+func (r *BIG) jacobi(p *BIG) int {
+       m:=0;
+       t:=NewBIGint(0)
+       x:=NewBIGint(0)
+       n:=NewBIGint(0)
+       zilch:=NewBIGint(0)
+       one:=NewBIGint(1)
+       if (p.parity()==0 || comp(r,zilch)==0 || comp(p,one)<=0) {return 0}
+       r.norm()
+       x.copy(r)
+       n.copy(p)
+       x.mod(p)
+
+       for comp(n,one)>0 {
+               if comp(x,zilch)==0 {return 0}
+               n8:=n.lastbits(3)
+               k:=0
+               for x.parity()==0 {
+                       k++
+                       x.shr(1)
+               }
+               if k%2==1 {m+=(n8*n8-1)/8}
+               m+=(n8-1)*(x.lastbits(2)-1)/4
+               t.copy(n)
+               t.mod(x)
+               n.copy(x)
+               x.copy(t)
+               m%=2
+
+       }
+       if m==0 {return 1}
+       return -1
+}
+
+/* this=1/this mod p. Binary method */
+func (r *BIG) invmodp(p *BIG) {
+       r.mod(p)
+       u:=NewBIGcopy(r)
+
+       v:=NewBIGcopy(p)
+       x1:=NewBIGint(1)
+       x2:=NewBIGint(0)
+       t:=NewBIGint(0)
+       one:=NewBIGint(1)
+       for (comp(u,one)!=0 && comp(v,one)!=0) {
+               for u.parity()==0 {
+                       u.shr(1);
+                       if x1.parity()!=0 {
+                               x1.add(p)
+                               x1.norm()
+                       }
+                       x1.shr(1)
+               }
+               for v.parity()==0 {
+                       v.shr(1);
+                       if x2.parity()!=0 {
+                               x2.add(p)
+                               x2.norm()
+                       }
+                       x2.shr(1)
+               }
+               if comp(u,v)>=0 {
+                       u.sub(v)
+                       u.norm()
+                       if comp(x1,x2)>=0 {
+                               x1.sub(x2)
+                       } else {
+                               t.copy(p)
+                               t.sub(x2)
+                               x1.add(t)
+                       }
+                       x1.norm()
+               } else {
+                       v.sub(u)
+                       v.norm()
+                       if comp(x2,x1)>=0 { 
+                               x2.sub(x1)
+                       } else {
+                               t.copy(p)
+                               t.sub(x1)
+                               x2.add(t)
+                       }
+                       x2.norm()
+               }
+       }
+       if comp(u,one)==0 {
+               r.copy(x1)
+       } else {r.copy(x2)}
+}
+
+/* return this^e mod m */
+func (r *BIG) powmod(e *BIG,m *BIG) *BIG {
+       r.norm()
+       e.norm()
+       a:=NewBIGint(1)
+       z:=NewBIGcopy(e)
+       s:=NewBIGcopy(r)
+       for true {
+               bt:=z.parity()
+               z.fshr(1)
+               if bt==1 {a=modmul(a,s,m)}
+               if z.iszilch() {break}
+               s=modsqr(s,m)
+       }
+       return a;
+}
+/*
+func main() {
+       a := NewBIGint(3)
+       m := NewBIGints(Modulus)
+
+       fmt.Printf("Modulus= "+m.toString())
+       fmt.Printf("\n")
+
+
+       e := NewBIGcopy(m);
+       e.dec(1); e.norm();
+       fmt.Printf("Exponent= "+e.toString())
+       fmt.Printf("\n")
+       a=a.powmod(e,m);
+       fmt.Printf("Result= "+a.toString())
+}
+*/

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/go/BenchtestEC.go
----------------------------------------------------------------------
diff --git a/version22/go/BenchtestEC.go b/version22/go/BenchtestEC.go
new file mode 100644
index 0000000..86510c0
--- /dev/null
+++ b/version22/go/BenchtestEC.go
@@ -0,0 +1,154 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* Test and benchmark elliptic curve and RSA functions */
+
+package main
+
+import "fmt"
+
+import "time"
+
+const MIN_TIME int=10
+const MIN_ITERS int=10
+
+func main() {
+
+       var RAW [100]byte
+       var P [RSA_RFS]byte
+       var M [RSA_RFS]byte
+       var C [RSA_RFS]byte
+
+       rng:=NewRAND()
+
+       rng.Clean();
+       for i:=0;i<100;i++ {RAW[i]=byte(i)}
+
+       rng.Seed(100,RAW[:])
+
+       pub:=New_rsa_public_key(FFLEN)
+       priv:=New_rsa_private_key(HFLEN)
+
+       if CURVETYPE==WEIERSTRASS {
+               fmt.Printf("Weierstrass parameterization\n")
+       }               
+       if CURVETYPE==EDWARDS {
+               fmt.Printf("Edwards parameterization\n")
+       }
+       if CURVETYPE==MONTGOMERY {
+               fmt.Printf("Montgomery parameterization\n")
+       }
+
+       if MODTYPE==PSEUDO_MERSENNE {
+               fmt.Printf("Pseudo-Mersenne Modulus\n")
+       }
+       if MODTYPE==MONTGOMERY_FRIENDLY {
+               fmt.Printf("Montgomery friendly Modulus\n")
+       }
+       if MODTYPE==GENERALISED_MERSENNE {
+               fmt.Printf("Generalised-Mersenne Modulus\n")
+       }
+       if MODTYPE==NOT_SPECIAL {
+               fmt.Printf("Not special Modulus\n")
+       }
+
+       fmt.Printf("Modulus size %d bits\n",MODBITS)
+       fmt.Printf("%d bit build\n",CHUNK)
+
+       var s *BIG
+       var G *ECP
+
+       gx:=NewBIGints(CURVE_Gx)
+       if CURVETYPE!=MONTGOMERY {
+               gy:=NewBIGints(CURVE_Gy)
+               G=NewECPbigs(gx,gy)
+       } else {
+               G=NewECPbig(gx)
+       }
+
+       r:=NewBIGints(CURVE_Order)
+       s=randomnum(r,rng)
+
+       WP:=G.mul(r)
+       if !WP.is_infinity() {
+               fmt.Printf("FAILURE - rG!=O\n")
+               return
+       }
+
+       start := time.Now()
+       iterations:=0
+       elapsed:=time.Since(start)
+       for (int(elapsed/time.Second))<MIN_TIME || iterations<MIN_ITERS {
+               WP=G.mul(s)
+               iterations++
+               elapsed=time.Since(start)
+       } 
+       dur:=float64(elapsed/time.Millisecond)/float64(iterations)
+       fmt.Printf("EC  mul - %8d iterations  ",iterations)
+       fmt.Printf(" %8.2f ms per iteration\n",dur)
+
+       fmt.Printf("Generating %d-bit RSA public/private key 
pair\n",FFLEN*BIGBITS);
+
+       start = time.Now()
+       iterations=0
+       elapsed=time.Since(start)
+       for (int(elapsed/time.Second))<MIN_TIME || iterations<MIN_ITERS {
+               RSA_KEY_PAIR(rng,65537,priv,pub)
+               iterations++
+               elapsed=time.Since(start)
+       } 
+       dur=float64(elapsed/time.Millisecond)/float64(iterations)
+       fmt.Printf("RSA gen - %8d iterations  ",iterations)
+       fmt.Printf(" %8.2f ms per iteration\n",dur)
+
+       for i:=0;i<RSA_RFS;i++ {M[i]=byte(i%128)};
+
+       start = time.Now()
+       iterations=0
+       elapsed=time.Since(start)
+       for (int(elapsed/time.Second))<MIN_TIME || iterations<MIN_ITERS {
+               RSA_ENCRYPT(pub,M[:],C[:])
+               iterations++
+               elapsed=time.Since(start)
+       } 
+       dur=float64(elapsed/time.Millisecond)/float64(iterations)
+       fmt.Printf("RSA enc - %8d iterations  ",iterations)
+       fmt.Printf(" %8.2f ms per iteration\n",dur)
+
+       start = time.Now()
+       iterations=0
+       elapsed=time.Since(start)
+       for (int(elapsed/time.Second))<MIN_TIME || iterations<MIN_ITERS {
+               RSA_DECRYPT(priv,C[:],P[:])
+               iterations++
+               elapsed=time.Since(start)
+       } 
+       dur=float64(elapsed/time.Millisecond)/float64(iterations)
+       fmt.Printf("RSA dec - %8d iterations  ",iterations)
+       fmt.Printf(" %8.2f ms per iteration\n",dur)
+
+       for i:=0;i<RSA_RFS;i++ {
+               if (P[i]!=M[i]) {
+                       fmt.Printf("FAILURE - RSA decryption\n")
+                       return
+               }
+       }
+
+       fmt.Printf("All tests pass\n")
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/go/BenchtestPAIR.go
----------------------------------------------------------------------
diff --git a/version22/go/BenchtestPAIR.go b/version22/go/BenchtestPAIR.go
new file mode 100644
index 0000000..bb1f710
--- /dev/null
+++ b/version22/go/BenchtestPAIR.go
@@ -0,0 +1,206 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* Test and benchmark elliptic curve and RSA functions */
+
+package main
+
+import "fmt"
+
+import "time"
+
+const MIN_TIME int=10
+const MIN_ITERS int=10
+
+func main() {
+       var RAW [100]byte
+
+       rng:=NewRAND()
+
+       rng.Clean();
+       for i:=0;i<100;i++ {RAW[i]=byte(i)}
+
+       rng.Seed(100,RAW[:])
+
+       if CURVE_PAIRING_TYPE==BN_CURVE {
+               fmt.Printf("BN Pairing-Friendly Curve\n")
+       }
+       if CURVE_PAIRING_TYPE==BLS_CURVE {
+               fmt.Printf("BLS Pairing-Friendly Curve\n")
+       }
+
+       fmt.Printf("Modulus size %d bits\n",MODBITS)
+       fmt.Printf("%d bit build\n",CHUNK)
+
+       G:=NewECPbigs(NewBIGints(CURVE_Gx),NewBIGints(CURVE_Gy))
+       r:=NewBIGints(CURVE_Order)
+       s:=randomnum(r,rng)
+
+       P:=G1mul(G,r)
+
+       if !P.is_infinity() {
+               fmt.Printf("FAILURE - rP!=O\n");
+               return;
+       }
+
+       start := time.Now()
+       iterations:=0
+       elapsed:=time.Since(start)
+       for (int(elapsed/time.Second))<MIN_TIME || iterations<MIN_ITERS {
+               P=G1mul(G,s)
+               iterations++
+               elapsed=time.Since(start)
+       } 
+       dur:=float64(elapsed/time.Millisecond)/float64(iterations)
+       fmt.Printf("G1 mul              - %8d iterations  ",iterations)
+       fmt.Printf(" %8.2f ms per iteration\n",dur)
+
+       
Q:=NewECP2fp2s(NewFP2bigs(NewBIGints(CURVE_Pxa),NewBIGints(CURVE_Pxb)),NewFP2bigs(NewBIGints(CURVE_Pya),NewBIGints(CURVE_Pyb)))
+       W:=G2mul(Q,r)
+
+       if !W.is_infinity() {
+               fmt.Printf("FAILURE - rQ!=O\n");
+               return;
+       }
+
+       start = time.Now()
+       iterations=0
+       elapsed=time.Since(start)
+       for (int(elapsed/time.Second))<MIN_TIME || iterations<MIN_ITERS {
+               W=G2mul(Q,s)
+               iterations++
+               elapsed=time.Since(start)
+       } 
+       dur=float64(elapsed/time.Millisecond)/float64(iterations)
+       fmt.Printf("G2 mul              - %8d iterations  ",iterations)
+       fmt.Printf(" %8.2f ms per iteration\n",dur)
+
+       w:=ate(Q,P)
+       w=fexp(w)
+
+       g:=GTpow(w,r)
+
+       if !g.isunity() {
+               fmt.Printf("FAILURE - g^r!=1\n");
+               return;
+       }
+
+       start = time.Now()
+       iterations=0
+       elapsed=time.Since(start)
+       for (int(elapsed/time.Second))<MIN_TIME || iterations<MIN_ITERS {
+               g=GTpow(w,s)
+               iterations++
+               elapsed=time.Since(start)
+       } 
+       dur=float64(elapsed/time.Millisecond)/float64(iterations)
+       fmt.Printf("GT pow              - %8d iterations  ",iterations)
+       fmt.Printf(" %8.2f ms per iteration\n",dur)
+
+       f:=NewFP2bigs(NewBIGints(CURVE_Fra),NewBIGints(CURVE_Frb))
+       q:=NewBIGints(Modulus)
+
+       m:=NewBIGcopy(q)
+       m.mod(r)
+
+       a:=NewBIGcopy(s)
+       a.mod(m)
+
+       b:=NewBIGcopy(s)
+       b.div(m)
+
+       g.copy(w)
+       c:=g.trace()
+
+       g.frob(f)
+       cp:=g.trace()
+
+       w.conj()
+       g.mul(w)
+       cpm1:=g.trace()
+       g.mul(w)
+       cpm2:=g.trace()
+
+       start = time.Now()
+       iterations=0
+       elapsed=time.Since(start)
+       for (int(elapsed/time.Second))<MIN_TIME || iterations<MIN_ITERS {
+               c=c.xtr_pow2(cp,cpm1,cpm2,a,b)
+               iterations++
+               elapsed=time.Since(start)
+       } 
+       dur=float64(elapsed/time.Millisecond)/float64(iterations)
+       fmt.Printf("GT pow (compressed) - %8d iterations  ",iterations)
+       fmt.Printf(" %8.2f ms per iteration\n",dur)
+
+       start = time.Now()
+       iterations=0
+       elapsed=time.Since(start)
+       for (int(elapsed/time.Second))<MIN_TIME || iterations<MIN_ITERS {
+               w=ate(Q,P)
+               iterations++
+               elapsed=time.Since(start)
+       } 
+       dur=float64(elapsed/time.Millisecond)/float64(iterations)
+       fmt.Printf("PAIRing ATE         - %8d iterations  ",iterations)
+       fmt.Printf(" %8.2f ms per iteration\n",dur)
+
+       start = time.Now()
+       iterations=0
+       elapsed=time.Since(start)
+       for (int(elapsed/time.Second))<MIN_TIME || iterations<MIN_ITERS {
+               g=fexp(w)
+               iterations++
+               elapsed=time.Since(start)
+       } 
+       dur=float64(elapsed/time.Millisecond)/float64(iterations)
+       fmt.Printf("PAIRing FEXP        - %8d iterations  ",iterations)
+       fmt.Printf(" %8.2f ms per iteration\n",dur)
+
+       P.copy(G)
+       Q.copy(W)
+
+       P=G1mul(P,s)
+
+       g=ate(Q,P)
+       g=fexp(g)
+
+       P.copy(G)
+       Q=G2mul(Q,s)
+
+       w=ate(Q,P)
+       w=fexp(w)
+
+       if !g.equals(w) {
+               fmt.Printf("FAILURE - e(sQ,p)!=e(Q,sP) \n")
+               return
+       }
+
+       Q.copy(W);
+       g=ate(Q,P)
+       g=fexp(g)
+       g=GTpow(g,s)
+
+       if !g.equals(w) {
+               fmt.Printf("FAILURE - e(sQ,p)!=e(Q,P)^s \n")
+               return
+       }
+
+       fmt.Printf("All tests pass\n") 
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/go/DBIG.go
----------------------------------------------------------------------
diff --git a/version22/go/DBIG.go b/version22/go/DBIG.go
new file mode 100644
index 0000000..b58b0c0
--- /dev/null
+++ b/version22/go/DBIG.go
@@ -0,0 +1,256 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* MiotCL double length DBIG number class */ 
+
+
+package main
+
+import "strconv"
+//import "fmt"
+
+func NewDBIG() *DBIG {
+       b:=new(DBIG)
+       for i:=0;i<DNLEN;i++ {
+               b.w[i]=0
+       }
+       return b
+}
+
+func NewDBIGcopy(x *DBIG) *DBIG {
+       b:=new(DBIG)
+       for i:=0;i<DNLEN;i++ {
+               b.w[i]=x.w[i]
+       }
+       return b
+}
+
+func NewDBIGscopy(x *BIG) *DBIG {
+       b:=new(DBIG)
+       for i:=0;i<NLEN-1;i++ {
+               b.w[i]=x.w[i]
+       }
+       b.w[NLEN-1]=x.get(NLEN-1)&BMASK /* top word normalized */
+       b.w[NLEN]=x.get(NLEN-1)>>BASEBITS
+
+       for i:=NLEN+1;i<DNLEN;i++  {b.w[i]=0}
+       return b
+}
+
+/* normalise this */
+func (r *DBIG) norm() {
+       carry:=Chunk(0)
+       for i:=0;i<DNLEN-1;i++ {
+               d:=r.w[i]+carry
+               r.w[i]=d&BMASK
+               carry=d>>BASEBITS
+       }
+       r.w[DNLEN-1]=(r.w[DNLEN-1]+carry)
+}
+
+/* split DBIG at position n, return higher half, keep lower half */
+func (r *DBIG) split(n uint) *BIG {
+       t:=NewBIG()
+       m:=n%BASEBITS;
+       carry:=r.w[DNLEN-1]<<(BASEBITS-m)
+
+       for i:=DNLEN-2;i>=NLEN-1;i-- {
+               nw:=(r.w[i]>>m)|carry;
+               carry=(r.w[i]<<(BASEBITS-m))&BMASK;
+               t.set(i-NLEN+1,nw);
+       }
+       r.w[NLEN-1]&=((Chunk(1)<<m)-1)
+       return t;
+}
+
+func (r *DBIG) cmove(g *DBIG,d int){
+       var b=Chunk(-d)
+
+       for i:=0;i<DNLEN;i++ {
+               r.w[i]^=(r.w[i]^g.w[i])&b
+       }
+}
+
+/* Compare a and b, return 0 if a==b, -1 if a<b, +1 if a>b. Inputs must be 
normalised */
+func dcomp(a *DBIG,b *DBIG) int {
+       for i:=DNLEN-1;i>=0;i-- {
+               if a.w[i]==b.w[i] {continue}
+               if a.w[i]>b.w[i] {
+                       return 1
+               } else  {return -1}
+       }
+       return 0
+}
+
+/* Copy from another BIG */
+func (r *DBIG) copy(x *DBIG) {
+       for i:=0;i<DNLEN;i++ {
+               r.w[i]=x.w[i]
+       }
+}
+
+func (r *DBIG) add(x *DBIG) {
+       for i:=0;i<DNLEN;i++ {
+               r.w[i]=r.w[i]+x.w[i] 
+       }
+}
+
+/* this-=x */
+func (r *DBIG) sub(x *DBIG) {
+       for i:=0;i<DNLEN;i++ {
+               r.w[i]=r.w[i]-x.w[i] 
+       }
+} 
+
+/* general shift left */
+func (r *DBIG) shl(k uint) {
+       n:=k%BASEBITS
+       m:=int(k/BASEBITS)
+
+       r.w[DNLEN-1]=((r.w[DNLEN-1-m]<<n))|(r.w[DNLEN-m-2]>>(BASEBITS-n))
+       for i:=DNLEN-2;i>m;i-- {
+               r.w[i]=((r.w[i-m]<<n)&BMASK)|(r.w[i-m-1]>>(BASEBITS-n))
+       }
+       r.w[m]=(r.w[0]<<n)&BMASK; 
+       for i:=0;i<m;i++ {r.w[i]=0}
+}
+
+/* general shift right */
+func (r *DBIG) shr(k uint) {
+       n:=(k%BASEBITS)
+       m:=int(k/BASEBITS)      
+       for i:=0;i<DNLEN-m-1;i++ {
+               r.w[i]=(r.w[m+i]>>n)|((r.w[m+i+1]<<(BASEBITS-n))&BMASK)
+       }
+       r.w[DNLEN-m-1]=r.w[DNLEN-1]>>n;
+       for i:=DNLEN-m;i<DNLEN;i++ {r.w[i]=0}
+}
+
+/* reduces this DBIG mod a BIG, and returns the BIG */
+func (r *DBIG) mod(c *BIG) *BIG {
+       r.norm()
+       m:=NewDBIGscopy(c)
+       dr:=NewDBIG();
+
+       if dcomp(r,m)<0 {
+               return NewBIGdcopy(r)
+       }
+
+       m.shl(1);
+       k:=1;
+               
+       for dcomp(r,m)>=0 {
+               m.shl(1);
+               k++;
+       }
+
+       for k>0 {
+               m.shr(1);
+
+               dr.copy(r);
+               dr.sub(m);
+               dr.norm();
+               r.cmove(dr,int(1-((dr.w[DNLEN-1]>>uint(CHUNK-1))&1)));
+/*
+               if dcomp(r,m)>=0 {
+                       r.sub(m);
+                       r.norm();
+               } */
+               k--;
+       }
+       return NewBIGdcopy(r)
+}
+
+/* return this/c */
+func (r *DBIG) div(c *BIG) *BIG {
+       var d int
+       k:=0
+       m:=NewDBIGscopy(c)
+       a:=NewBIGint(0)
+       e:=NewBIGint(1)
+       sr:=NewBIG()
+       dr:=NewDBIG()
+       r.norm()
+
+       for dcomp(r,m)>=0 {
+               e.fshl(1)
+               m.shl(1)
+               k++
+       }
+
+       for k>0 {
+               m.shr(1)
+               e.shr(1)
+
+               dr.copy(r);
+               dr.sub(m);
+               dr.norm();
+               d=int(1-((dr.w[DNLEN-1]>>uint(CHUNK-1))&1));
+               r.cmove(dr,d);
+               sr.copy(a);
+               sr.add(e);
+               sr.norm();
+               a.cmove(sr,d);
+
+/*
+               if dcomp(r,m)>0 {
+                       a.add(e)
+                       a.norm()
+                       r.sub(m)
+                       r.norm()
+               } */
+               k--
+       }
+       return a
+}
+
+/* Convert to Hex String */
+func (r *DBIG) toString() string {
+       s:=""
+       len:=r.nbits()
+
+       if len%4==0 {
+               len/=4
+       } else {
+               len/=4 
+               len++
+
+       }
+
+       for i:=len-1;i>=0;i-- {
+               b:=NewDBIGcopy(r)
+               
+               b.shr(uint(i*4))
+               s+=strconv.FormatInt(int64(b.w[0]&15),16)
+       }
+       return s
+}
+
+/* return number of bits */
+func (r *DBIG) nbits() int {
+       k:=DNLEN-1
+       r.norm()
+       for (k>=0 && r.w[k]==0) {k--}
+       if k<0 {return 0}
+       bts:=int(BASEBITS)*k;
+       c:=r.w[k];
+       for c!=0 {c/=2; bts++}
+       return bts
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/go/ECDH.go
----------------------------------------------------------------------
diff --git a/version22/go/ECDH.go b/version22/go/ECDH.go
new file mode 100644
index 0000000..9656113
--- /dev/null
+++ b/version22/go/ECDH.go
@@ -0,0 +1,547 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/* Elliptic Curve API high-level functions  */
+
+package main
+
+//import "fmt"
+
+const ECDH_INVALID_PUBLIC_KEY int=-2
+const ECDH_ERROR int=-3
+const ECDH_INVALID int=-4
+const ECDH_EFS int=int(MODBYTES)
+const ECDH_EGS int=int(MODBYTES)
+const ECDH_EAS int=16
+const ECDH_EBS int=16
+const ECDH_SHA256 int=32
+const ECDH_SHA384 int=48
+const ECDH_SHA512 int=64
+
+const ECDH_HASH_TYPE int=ECDH_SHA512
+
+/* Convert Integer to n-byte array */
+func inttoBytes(n int,len int) []byte {
+       var b []byte
+       var i int
+       for i=0;i<len;i++ {b=append(b,0)}
+       i=len
+       for (n>0 && i>0) {
+               i--;
+               b[i]=byte(n&0xff)
+               n/=256
+       }       
+       return b
+}
+
+func ehashit(sha int,A []byte,n int,B []byte,pad int) []byte {
+       var R []byte
+       if sha==ECDH_SHA256 {
+               H:=NewHASH256()
+               H.Process_array(A)
+               if n>0 {H.Process_num(int32(n))}
+               if B!=nil {H.Process_array(B)}
+               R=H.Hash()
+       }
+       if sha==ECDH_SHA384 {
+               H:=NewHASH384()
+               H.Process_array(A)
+               if n>0 {H.Process_num(int32(n))}
+               if B!=nil {H.Process_array(B)}
+               R=H.Hash()
+       }
+       if sha==ECDH_SHA512 {
+               H:=NewHASH512()
+               H.Process_array(A)
+               if n>0 {H.Process_num(int32(n))}
+               if B!=nil {H.Process_array(B)}
+               R=H.Hash()
+       }
+       if R==nil {return nil}
+
+       if pad==0 {return R}
+       var W []byte
+       for i:=0;i<pad;i++ {W=append(W,0)}
+       if pad<=sha {
+               for i:=0;i<pad;i++ {W[i]=R[i]}
+       } else {
+               for i:=0;i<sha;i++ {W[i]=R[i]}
+               for i:=sha;i<pad;i++ {W[i]=0}
+       }
+       return W
+}
+
+/* Key Derivation Functions */
+/* Input octet Z */
+/* Output key of length olen */
+func KDF1(sha int,Z []byte,olen int) []byte {
+/* NOTE: the parameter olen is the length of the output K in bytes */
+       hlen:=sha
+       var K []byte
+       k:=0
+    
+       for i:=0;i<olen;i++ {K=append(K,0)}
+
+       cthreshold:=olen/hlen; if olen%hlen!=0 {cthreshold++}
+
+       for counter:=0;counter<cthreshold;counter++ {
+               B:=ehashit(sha,Z,counter,nil,0)
+               if k+hlen>olen {
+                       for i:=0;i<olen%hlen;i++ {K[k]=B[i]; k++}
+               } else {
+                       for i:=0;i<hlen;i++ {K[k]=B[i]; k++}
+               }
+       }
+       return K;
+}
+
+func KDF2(sha int,Z []byte,P []byte,olen int) []byte {
+/* NOTE: the parameter olen is the length of the output k in bytes */
+       hlen:=sha
+       var K []byte
+       k:=0
+    
+       for i:=0;i<olen;i++ {K=append(K,0)}
+
+       cthreshold:=olen/hlen; if olen%hlen!=0 {cthreshold++}
+
+       for counter:=1;counter<=cthreshold;counter++ {
+               B:=ehashit(sha,Z,counter,P,0)
+               if k+hlen>olen {
+                       for i:=0;i<olen%hlen;i++ {K[k]=B[i]; k++}
+               } else {
+                       for i:=0;i<hlen;i++ {K[k]=B[i]; k++}
+               }
+       }
+       return K
+}
+
+/* Password based Key Derivation Function */
+/* Input password p, salt s, and repeat count */
+/* Output key of length olen */
+func PBKDF2(sha int,Pass []byte,Salt []byte,rep int,olen int) []byte {
+       d:=olen/sha; if olen%sha!=0 {d++}
+
+       var F []byte
+       var U []byte
+       var S []byte
+       var K []byte
+       
+       for i:=0;i<sha;i++{F=append(F,0); U=append(U,0)}
+
+       for i:=1;i<=d;i++ {
+               for j:=0;j<len(Salt);j++ {S=append(S,Salt[j])} 
+               N:=inttoBytes(i,4)
+               for j:=0;j<4;j++ {S=append(S,N[j])}   
+
+               HMAC(sha,S,Pass,F[:])
+
+               for j:=0;j<sha;j++ {U[j]=F[j]}
+               for j:=2;j<=rep;j++ {
+                       HMAC(sha,U[:],Pass,U[:]);
+                       for k:=0;k<sha;k++ {F[k]^=U[k]}
+               }
+               for j:=0;j<sha;j++ {K=append(K,F[j])} 
+       }
+       var key []byte
+       for i:=0;i<olen;i++ {key=append(key,K[i])}
+       return key
+}
+
+/* Calculate HMAC of m using key k. HMAC is tag of length olen (which is 
length of tag) */
+func HMAC(sha int,M []byte,K []byte,tag []byte) int {
+       /* Input is from an octet m        *
+       * olen is requested output length in bytes. k is the key  *
+       * The output is the calculated tag */
+       var B []byte
+       b:=64
+       if sha>32 {b=128}
+
+       var K0 [128]byte
+       olen:=len(tag)
+
+       if (olen<4 /*|| olen>sha */) {return 0}
+
+       for i:=0;i<b;i++ {K0[i]=0}
+
+       if len(K) > b {
+               B=ehashit(sha,K,0,nil,0) 
+               for i:=0;i<sha;i++ {K0[i]=B[i]}
+       } else {
+               for i:=0;i<len(K);i++  {K0[i]=K[i]}
+       }
+               
+       for i:=0;i<b;i++ {K0[i]^=0x36}
+       B=ehashit(sha,K0[0:b],0,M,0);
+
+       for i:=0;i<b;i++ {K0[i]^=0x6a}
+       B=ehashit(sha,K0[0:b],0,B,olen)
+
+       for i:=0;i<olen;i++ {tag[i]=B[i]}
+
+       return 1
+}
+
+/* AES encryption/decryption. Encrypt byte array M using key K and returns 
ciphertext */
+func AES_CBC_IV0_ENCRYPT(K []byte,M []byte) []byte { /* AES CBC encryption, 
with Null IV and key K */
+       /* Input is from an octet string M, output is to an octet string C */
+       /* Input is padded as necessary to make up a full final block */
+       a:=NewAES()
+       fin:=false
+
+       var buff [16]byte
+       var C []byte
+
+       a.Init(aes_CBC,len(K),K,nil)
+
+       ipt:=0; //opt:=0
+       var i int
+       for true {
+               for i=0;i<16;i++ {
+                       if ipt<len(M) {
+                               buff[i]=M[ipt]; ipt++;
+                       } else {fin=true; break;}
+               }
+               if fin {break}
+               a.Encrypt(buff[:])
+               for i=0;i<16;i++ {
+                       C=append(C,buff[i])
+               }
+       }    
+
+/* last block, filled up to i-th index */
+
+       padlen:=16-i
+       for j:=i;j<16;j++ {buff[j]=byte(padlen)}
+
+       a.Encrypt(buff[:])
+
+       for i=0;i<16;i++ {
+               C=append(C,buff[i])
+       }
+       a.End()   
+       return C
+}
+
+/* returns plaintext if all consistent, else returns null string */
+func AES_CBC_IV0_DECRYPT(K []byte,C []byte) []byte { /* padding is removed */
+       a:=NewAES()
+       var buff [16]byte
+       var MM []byte
+       var M []byte
+
+       var i int
+       ipt:=0; opt:=0
+
+       a.Init(aes_CBC,len(K),K,nil);
+
+       if len(C)==0 {return nil}
+       ch:=C[ipt]; ipt++
+  
+       fin:=false
+
+       for true {
+               for i=0;i<16;i++ {
+                       buff[i]=ch    
+                       if ipt>=len(C) {
+                               fin=true; break
+                       }  else {ch=C[ipt]; ipt++ }
+               }
+               a.Decrypt(buff[:])
+               if fin {break}
+               for i=0;i<16;i++ {
+                       MM=append(MM,buff[i]); opt++
+               }
+       }    
+
+       a.End();
+       bad:=false
+       padlen:=int(buff[15])
+       if (i!=15 || padlen<1 || padlen>16) {bad=true}
+       if (padlen>=2 && padlen<=16) {
+               for i=16-padlen;i<16;i++ {
+                       if buff[i]!=byte(padlen) {bad=true}
+               }
+       }
+    
+       if !bad { 
+               for i=0;i<16-padlen;i++ {
+                       MM=append(MM,buff[i]); opt++
+               }
+       }
+
+       if bad {return nil}
+
+       for i=0;i<opt;i++ {M=append(M,MM[i])}
+
+       return M;
+}
+
+/* Calculate a public/private EC GF(p) key pair W,S where W=S.G mod EC(p),
+ * where S is the secret key and W is the public key
+ * and G is fixed generator.
+ * If RNG is NULL then the private key is provided externally in S
+ * otherwise it is generated randomly internally */
+func ECDH_KEY_PAIR_GENERATE(RNG *RAND,S []byte,W []byte) int {
+       res:=0
+//     var T [ECDH_EFS]byte
+       var s *BIG
+       var G *ECP
+
+       gx:=NewBIGints(CURVE_Gx)
+       if CURVETYPE!=MONTGOMERY {
+               gy:=NewBIGints(CURVE_Gy)
+               G=NewECPbigs(gx,gy)
+       } else {
+               G=NewECPbig(gx)
+       }
+
+       r:=NewBIGints(CURVE_Order)
+
+       if RNG==nil {
+               s=fromBytes(S)
+               s.mod(r)
+       } else {
+               s=randomnum(r,RNG)
+               
+       //      s.toBytes(T[:])
+       //      for i:=0;i<ECDH_EGS;i++ {S[i]=T[i]}
+       }
+
+       if AES_S>0 {
+               s.mod2m(2*AES_S)
+       }
+       s.toBytes(S)
+
+       WP:=G.mul(s)
+
+       WP.toBytes(W)
+
+       return res
+}
+
+/* validate public key. Set full=true for fuller check */
+func ECDH_PUBLIC_KEY_VALIDATE(full bool,W []byte) int {
+       WP:=ECP_fromBytes(W)
+       res:=0
+
+       r:=NewBIGints(CURVE_Order)
+
+       if WP.is_infinity() {res=ECDH_INVALID_PUBLIC_KEY}
+       if res==0 && full {
+               WP=WP.mul(r)
+               if !WP.is_infinity() {res=ECDH_INVALID_PUBLIC_KEY} 
+       }
+       return res
+}
+
+/* IEEE-1363 Diffie-Hellman online calculation Z=S.WD */
+func ECPSVDP_DH(S []byte,WD []byte,Z []byte) int {
+       res:=0;
+       var T [ECDH_EFS]byte
+
+       s:=fromBytes(S)
+
+       W:=ECP_fromBytes(WD)
+       if W.is_infinity() {res=ECDH_ERROR}
+
+       if res==0 {
+               r:=NewBIGints(CURVE_Order)
+               s.mod(r)
+               W=W.mul(s)
+               if W.is_infinity() { 
+                       res=ECDH_ERROR
+               } else {
+                       W.getX().toBytes(T[:])
+                       for i:=0;i<ECDH_EFS;i++ {Z[i]=T[i]}
+               }
+       }
+       return res
+}
+
+/* IEEE ECDSA Signature, C and D are signature on F using private key S */
+func ECPSP_DSA(sha int,RNG *RAND,S []byte,F []byte,C []byte,D []byte) int {
+       var T [ECDH_EFS]byte
+
+       B:=ehashit(sha,F,0,nil,int(MODBYTES));
+
+       gx:=NewBIGints(CURVE_Gx)
+       gy:=NewBIGints(CURVE_Gy)
+
+       G:=NewECPbigs(gx,gy)
+       r:=NewBIGints(CURVE_Order)
+
+       s:=fromBytes(S)
+       f:=fromBytes(B[:])
+
+       c:=NewBIGint(0)
+       d:=NewBIGint(0)
+       V:=NewECP()
+
+       for d.iszilch() {
+               u:=randomnum(r,RNG);
+               w:=randomnum(r,RNG);
+               if AES_S>0 {
+                       u.mod2m(2*AES_S)
+               }                       
+               V.copy(G)
+               V=V.mul(u)              
+               vx:=V.getX()
+               c.copy(vx)
+               c.mod(r);
+               if c.iszilch() {continue}
+               u.copy(modmul(u,w,r))
+               u.invmodp(r)
+               d.copy(modmul(s,c,r))
+               d.add(f)
+               d.copy(modmul(d,w,r))
+               d.copy(modmul(u,d,r))
+       } 
+       
+       c.toBytes(T[:])
+       for i:=0;i<ECDH_EFS;i++ {C[i]=T[i]}
+       d.toBytes(T[:])
+       for i:=0;i<ECDH_EFS;i++ {D[i]=T[i]}
+       return 0
+}
+
+/* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified 
using public key W */
+func ECPVP_DSA(sha int,W []byte,F []byte,C []byte,D []byte) int {
+       res:=0
+
+       B:=ehashit(sha,F,0,nil,int(MODBYTES));
+
+       gx:=NewBIGints(CURVE_Gx)
+       gy:=NewBIGints(CURVE_Gy)
+
+       G:=NewECPbigs(gx,gy)
+       r:=NewBIGints(CURVE_Order)
+
+       c:=fromBytes(C)
+       d:=fromBytes(D)
+       f:=fromBytes(B[:])
+     
+       if (c.iszilch() || comp(c,r)>=0 || d.iszilch() || comp(d,r)>=0) {
+            res=ECDH_INVALID;
+       }
+
+       if res==0 {
+               d.invmodp(r)
+               f.copy(modmul(f,d,r))
+               h2:=modmul(c,d,r)
+
+               WP:=ECP_fromBytes(W)
+               if WP.is_infinity() {
+                       res=ECDH_ERROR
+               } else {
+                       P:=NewECP()
+                       P.copy(WP)
+
+                       P=P.mul2(h2,G,f)
+
+                       if P.is_infinity() {
+                               res=ECDH_INVALID;
+                       } else {
+                               d=P.getX()
+                               d.mod(r)
+
+                               if comp(d,c)!=0 {res=ECDH_INVALID}
+                       }
+               }
+       }
+
+       return res
+}
+
+/* IEEE1363 ECIES encryption. Encryption of plaintext M uses public key W and 
produces ciphertext V,C,T */
+func ECIES_ENCRYPT(sha int,P1 []byte,P2 []byte,RNG *RAND,W []byte,M []byte,V 
[]byte,T []byte) []byte { 
+       var Z [ECDH_EFS]byte
+       var VZ [3*ECDH_EFS+1]byte
+       var K1 [ECDH_EAS]byte
+       var K2 [ECDH_EAS]byte
+       var U [ECDH_EGS]byte
+
+       if ECDH_KEY_PAIR_GENERATE(RNG,U[:],V)!=0 {return nil}
+       if ECPSVDP_DH(U[:],W,Z[:])!=0 {return nil}     
+
+       for i:=0;i<2*ECDH_EFS+1;i++ {VZ[i]=V[i]}
+       for i:=0;i<ECDH_EFS;i++ {VZ[2*ECDH_EFS+1+i]=Z[i]}
+
+
+       K:=KDF2(sha,VZ[:],P1,ECDH_EFS)
+
+       for i:=0;i<ECDH_EAS;i++ {K1[i]=K[i]; K2[i]=K[ECDH_EAS+i]} 
+
+       C:=AES_CBC_IV0_ENCRYPT(K1[:],M)
+
+       L2:=inttoBytes(len(P2),8)       
+       
+       var AC []byte
+
+       for i:=0;i<len(C);i++ {AC=append(AC,C[i])}   
+       for i:=0;i<len(P2);i++ {AC=append(AC,P2[i])}
+       for i:=0;i<8;i++ {AC=append(AC,L2[i])}
+       
+       HMAC(sha,AC,K2[:],T)
+
+       return C
+}
+
+/* IEEE1363 ECIES decryption. Decryption of ciphertext V,C,T using private key 
U outputs plaintext M */
+func ECIES_DECRYPT(sha int,P1 []byte,P2 []byte,V []byte,C []byte,T []byte,U 
[]byte) []byte { 
+       var Z [ECDH_EFS]byte
+       var VZ [3*ECDH_EFS+1]byte
+       var K1 [ECDH_EAS]byte
+       var K2 [ECDH_EAS]byte
+
+       var TAG []byte =T[:]  
+
+       if ECPSVDP_DH(U,V,Z[:])!=0 {return nil}
+
+       for i:=0;i<2*ECDH_EFS+1;i++ {VZ[i]=V[i]}
+       for i:=0;i<ECDH_EFS;i++ {VZ[2*ECDH_EFS+1+i]=Z[i]}
+
+       K:=KDF2(sha,VZ[:],P1,ECDH_EFS)
+
+       for i:=0;i<ECDH_EAS;i++ {K1[i]=K[i]; K2[i]=K[ECDH_EAS+i]} 
+
+       M:=AES_CBC_IV0_DECRYPT(K1[:],C)
+
+       if M==nil {return nil}
+
+       L2:=inttoBytes(len(P2),8)       
+       
+       var AC []byte
+       
+       for i:=0;i<len(C);i++ {AC=append(AC,C[i])}   
+       for i:=0;i<len(P2);i++ {AC=append(AC,P2[i])}
+       for i:=0;i<8;i++ {AC=append(AC,L2[i])}
+       
+       HMAC(sha,AC,K2[:],TAG)
+
+       same:=true
+       for i:=0;i<len(T);i++ {
+               if T[i]!=TAG[i] {same=false}
+       }
+       if !same {return nil}
+       
+       return M
+}
+
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/go/ECP.go
----------------------------------------------------------------------
diff --git a/version22/go/ECP.go b/version22/go/ECP.go
new file mode 100644
index 0000000..e33b52b
--- /dev/null
+++ b/version22/go/ECP.go
@@ -0,0 +1,893 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+package main
+
+//import "fmt"
+
+/* Elliptic Curve Point Structure */
+
+type ECP struct {
+       x *FP
+       y *FP
+       z *FP
+       INF bool
+}
+
+/* Constructors */
+func NewECP() *ECP {
+       E:=new(ECP)
+       E.x=NewFPint(0)
+       E.y=NewFPint(0)
+       E.z=NewFPint(0)
+       E.INF=true
+       return E
+}
+
+/* set (x,y) from two BIGs */
+func NewECPbigs(ix *BIG,iy *BIG) *ECP {
+       E:=new(ECP)
+       E.x=NewFPbig(ix)
+       E.y=NewFPbig(iy)
+       E.z=NewFPint(1)
+       rhs:=RHS(E.x)
+
+       if CURVETYPE==MONTGOMERY {
+               if rhs.jacobi()==1 {
+                       E.INF=false
+               } else {E.inf()}
+       } else {
+               y2:=NewFPcopy(E.y)
+               y2.sqr()
+               if y2.equals(rhs) {
+                       E.INF=false
+               } else {E.inf()}
+       }
+       return E
+}
+
+/* set (x,y) from BIG and a bit */
+func NewECPbigint(ix *BIG,s int) *ECP {
+       E:=new(ECP)
+       E.x=NewFPbig(ix)
+       E.y=NewFPint(0)
+       rhs:=RHS(E.x)
+       E.z=NewFPint(1)
+       if rhs.jacobi()==1 {
+               ny:=rhs.sqrt()
+               if ny.redc().parity()!=s {ny.neg()}
+               E.y.copy(ny)
+               E.INF=false
+       } else {E.inf()}
+       return E;
+}
+
+/* set from x - calculate y from curve equation */
+func NewECPbig(ix *BIG) *ECP {
+       E:=new(ECP)     
+       E.x=NewFPbig(ix)
+       E.y=NewFPint(0)
+       rhs:=RHS(E.x)
+       E.z=NewFPint(1)
+       if rhs.jacobi()==1 {
+               if CURVETYPE!=MONTGOMERY {E.y.copy(rhs.sqrt())}
+               E.INF=false
+       } else {E.INF=true}
+       return E
+}
+
+/* test for O point-at-infinity */
+func (E *ECP) is_infinity() bool {
+       if CURVETYPE==EDWARDS {
+               E.x.reduce(); E.y.reduce(); E.z.reduce()
+               return (E.x.iszilch() && E.y.equals(E.z))
+       } else {return E.INF}
+}
+
+/* Conditional swap of P and Q dependant on d */
+func (E *ECP) cswap(Q *ECP,d int) {
+       E.x.cswap(Q.x,d)
+       if CURVETYPE!=MONTGOMERY {E.y.cswap(Q.y,d)}
+       E.z.cswap(Q.z,d)
+       if CURVETYPE!=EDWARDS {
+               bd:=true
+               if d==0 {bd=false}
+               bd=bd&&(E.INF!=Q.INF)
+               E.INF=(bd!=E.INF)
+               Q.INF=(bd!=Q.INF)
+       }
+}
+
+/* Conditional move of Q to P dependant on d */
+func (E *ECP) cmove(Q *ECP,d int) {
+       E.x.cmove(Q.x,d)
+       if CURVETYPE!=MONTGOMERY {E.y.cmove(Q.y,d)}
+       E.z.cmove(Q.z,d);
+       if CURVETYPE!=EDWARDS {
+               bd:=true
+               if d==0 {bd=false}
+               E.INF=(E.INF!=((E.INF!=Q.INF)&&bd))
+       }
+}
+
+/* return 1 if b==c, no branching */
+func teq(b int32,c int32) int {
+       x:=b^c
+       x-=1  // if x=0, x now -1
+       return int((x>>31)&1)
+}
+
+/* this=P */
+func (E *ECP) copy(P *ECP) {
+       E.x.copy(P.x);
+       if CURVETYPE!=MONTGOMERY {E.y.copy(P.y)}
+       E.z.copy(P.z);
+       E.INF=P.INF;
+}
+
+/* this=-this */
+func (E *ECP) neg() {
+       if E.is_infinity() {return}
+       if CURVETYPE==WEIERSTRASS {
+               E.y.neg(); E.y.norm()
+       }
+       if CURVETYPE==EDWARDS {
+               E.x.neg(); E.x.norm()
+       }
+       return;
+}
+
+/* Constant time select from pre-computed table */
+func (E *ECP) selector(W []*ECP,b int32) {
+       MP:=NewECP()
+       m:=b>>31;
+       babs:=(b^m)-m;
+
+       babs=(babs-1)/2
+
+       E.cmove(W[0],teq(babs,0))  // conditional move
+       E.cmove(W[1],teq(babs,1))
+       E.cmove(W[2],teq(babs,2))
+       E.cmove(W[3],teq(babs,3))
+       E.cmove(W[4],teq(babs,4))
+       E.cmove(W[5],teq(babs,5))
+       E.cmove(W[6],teq(babs,6))
+       E.cmove(W[7],teq(babs,7))
+ 
+       MP.copy(E);
+       MP.neg()
+       E.cmove(MP,int(m&1));
+}
+
+/* set this=O */
+func (E *ECP) inf() {
+       E.INF=true;
+       E.x.zero()
+       E.y.one()
+       E.z.one()
+}
+
+/* Test P == Q */
+func( E *ECP) equals(Q *ECP) bool {
+       if E.is_infinity() && Q.is_infinity() {return true}
+       if E.is_infinity() || Q.is_infinity() {return false}
+       if CURVETYPE==WEIERSTRASS {
+               zs2:=NewFPcopy(E.z); zs2.sqr()
+               zo2:=NewFPcopy(Q.z); zo2.sqr()
+               zs3:=NewFPcopy(zs2); zs3.mul(E.z)
+               zo3:=NewFPcopy(zo2); zo3.mul(Q.z)
+               zs2.mul(Q.x)
+               zo2.mul(E.x)
+               if !zs2.equals(zo2) {return false}
+               zs3.mul(Q.y)
+               zo3.mul(E.y)
+               if !zs3.equals(zo3) {return false}
+       } else {
+               a:=NewFPint(0)
+               b:=NewFPint(0)
+               a.copy(E.x); a.mul(Q.z); a.reduce()
+               b.copy(Q.x); b.mul(E.z); b.reduce()
+               if !a.equals(b) {return false}
+               if CURVETYPE==EDWARDS {
+                       a.copy(E.y); a.mul(Q.z); a.reduce()
+                       b.copy(Q.y); b.mul(E.z); b.reduce()
+                       if !a.equals(b) {return false}
+               }
+       }
+       return true
+}
+
+/* Calculate RHS of curve equation */
+func RHS(x *FP) *FP {
+       x.norm()
+       r:=NewFPcopy(x)
+       r.sqr();
+
+       if CURVETYPE==WEIERSTRASS { // x^3+Ax+B
+               b:=NewFPbig(NewBIGints(CURVE_B))
+               r.mul(x);
+               if CURVE_A==-3 {
+                       cx:=NewFPcopy(x)
+                       cx.imul(3)
+                       cx.neg(); cx.norm()
+                       r.add(cx)
+               }
+               r.add(b)
+       }
+       if CURVETYPE==EDWARDS { // (Ax^2-1)/(Bx^2-1) 
+               b:=NewFPbig(NewBIGints(CURVE_B))
+
+               one:=NewFPint(1)
+               b.mul(r)
+               b.sub(one)
+               if CURVE_A==-1 {r.neg()}
+               r.sub(one)
+               b.inverse()
+               r.mul(b)
+       }
+       if CURVETYPE==MONTGOMERY { // x^3+Ax^2+x
+               x3:=NewFPint(0)
+               x3.copy(r)
+               x3.mul(x)
+               r.imul(CURVE_A)
+               r.add(x3)
+               r.add(x)
+       }
+       r.reduce()
+       return r
+}
+
+/* set to affine - from (x,y,z) to (x,y) */
+func (E *ECP) affine() {
+       if E.is_infinity() {return}
+       one:=NewFPint(1)
+       if E.z.equals(one) {return}
+       E.z.inverse()
+       if CURVETYPE==WEIERSTRASS {
+               z2:=NewFPcopy(E.z)
+               z2.sqr()
+               E.x.mul(z2); E.x.reduce()
+               E.y.mul(z2)
+               E.y.mul(E.z);  E.y.reduce()
+       }
+       if CURVETYPE==EDWARDS {
+               E.x.mul(E.z); E.x.reduce()
+               E.y.mul(E.z); E.y.reduce()
+       }
+       if CURVETYPE==MONTGOMERY {
+               E.x.mul(E.z); E.x.reduce()
+       }
+       E.z.one()
+}
+
+/* extract x as a BIG */
+func (E *ECP) getX() *BIG {
+       E.affine()
+       return E.x.redc()
+}
+/* extract y as a BIG */
+func (E *ECP) getY() *BIG {
+       E.affine()
+       return E.y.redc()
+}
+
+/* get sign of Y */
+func (E *ECP) getS() int {
+       E.affine()
+       y:=E.getY()
+       return y.parity()
+}
+/* extract x as an FP */
+func (E *ECP) getx() *FP {
+       return E.x;
+}
+/* extract y as an FP */
+func (E *ECP) gety() *FP {
+       return E.y
+}
+/* extract z as an FP */
+func (E *ECP) getz() *FP {
+       return E.z
+}
+
+/* convert to byte array */
+func (E *ECP) toBytes(b []byte) {
+       var t [int(MODBYTES)]byte
+       MB:=int(MODBYTES)
+       if CURVETYPE!=MONTGOMERY {
+               b[0]=0x04
+       } else {b[0]=0x02}
+       
+       E.affine()
+       E.x.redc().toBytes(t[:])
+       for i:=0;i<MB;i++ {b[i+1]=t[i]}
+       if CURVETYPE!=MONTGOMERY {
+               E.y.redc().toBytes(t[:])
+               for i:=0;i<MB;i++ {b[i+MB+1]=t[i]}
+       }
+}
+
+/* convert from byte array to point */
+func ECP_fromBytes(b []byte) *ECP {
+       var t [int(MODBYTES)]byte
+       MB:=int(MODBYTES)
+       p:=NewBIGints(Modulus)
+
+       for i:=0;i<MB;i++ {t[i]=b[i+1]}
+       px:=fromBytes(t[:])
+       if comp(px,p)>=0 {return NewECP()}
+
+       if (b[0]==0x04) {
+               for i:=0;i<MB;i++ {t[i]=b[i+MB+1]}
+               py:=fromBytes(t[:])
+               if comp(py,p)>=0 {return NewECP()}
+               return NewECPbigs(px,py)
+       } else {return NewECPbig(px)}
+}
+
+/* convert to hex string */
+func (E *ECP) toString() string {
+       if E.is_infinity() {return "infinity"}
+       E.affine();
+       if CURVETYPE==MONTGOMERY {
+               return "("+E.x.redc().toString()+")"
+       } else {return "("+E.x.redc().toString()+","+E.y.redc().toString()+")"}
+}
+
+/* this*=2 */
+func (E *ECP) dbl() {
+       if CURVETYPE==WEIERSTRASS {
+               if E.INF {return}
+               if E.y.iszilch() {
+                       E.inf()
+                       return
+               }
+
+               w1:=NewFPcopy(E.x);
+               w6:=NewFPcopy(E.z);
+               w2:=NewFPint(0);
+               w3:=NewFPcopy(E.x)
+               w8:=NewFPcopy(E.x)
+
+               if CURVE_A==-3 {
+                       w6.sqr()
+                       w1.copy(w6)
+                       w1.neg()
+                       w3.add(w1)
+
+                       w8.add(w6)
+
+                       w3.mul(w8)
+                       w8.copy(w3)
+                       w8.imul(3)
+               } else {
+                       w1.sqr()
+                       w8.copy(w1)
+                       w8.imul(3)
+               }
+
+               w2.copy(E.y); w2.sqr()
+               w3.copy(E.x); w3.mul(w2)
+               w3.imul(4)
+               w1.copy(w3); w1.neg()
+       //              w1.norm();
+
+
+               E.x.copy(w8); E.x.sqr()
+               E.x.add(w1)
+               E.x.add(w1)
+       //              x.reduce();
+               E.x.norm()
+
+               E.z.mul(E.y)
+               E.z.add(E.z)
+
+               w2.add(w2)
+               w2.sqr()
+               w2.add(w2)
+               w3.sub(E.x)
+               E.y.copy(w8); E.y.mul(w3);
+       //              w2.norm();
+               E.y.sub(w2)
+       //              y.reduce();
+       //              z.reduce();
+               E.y.norm()
+               E.z.norm()
+
+       }
+       if CURVETYPE==EDWARDS {
+               C:=NewFPcopy(E.x)
+               D:=NewFPcopy(E.y)
+               H:=NewFPcopy(E.z)
+               J:=NewFPint(0)
+       
+               E.x.mul(E.y); E.x.add(E.x)
+               C.sqr()
+               D.sqr()
+               if CURVE_A==-1 {C.neg()}        
+               E.y.copy(C); E.y.add(D)
+       //              y.norm();
+               H.sqr(); H.add(H)
+               E.z.copy(E.y)
+               J.copy(E.y); J.sub(H)
+               E.x.mul(J)
+               C.sub(D)
+               E.y.mul(C)
+               E.z.mul(J)
+
+               E.x.norm()
+               E.y.norm()
+               E.z.norm()
+       }
+       if CURVETYPE==MONTGOMERY {
+               A:=NewFPcopy(E.x)
+               B:=NewFPcopy(E.x)       
+               AA:=NewFPint(0)
+               BB:=NewFPint(0)
+               C:=NewFPint(0)
+       
+               if E.INF {return}
+
+               A.add(E.z)
+               AA.copy(A); AA.sqr()
+               B.sub(E.z)
+               BB.copy(B); BB.sqr()
+               C.copy(AA); C.sub(BB)
+       //              C.norm();
+
+               E.x.copy(AA); E.x.mul(BB)
+
+               A.copy(C); A.imul((CURVE_A+2)/4)
+
+               BB.add(A)
+               E.z.copy(BB); E.z.mul(C)
+       //              x.reduce();
+       //              z.reduce();
+               E.x.norm()
+               E.z.norm()
+       }
+       return;
+}
+
+/* this+=Q */
+func (E *ECP) add(Q *ECP) {
+       if CURVETYPE==WEIERSTRASS {
+               if E.INF {
+                       E.copy(Q)
+                       return
+               }
+               if Q.INF {return}
+
+               aff:=false
+
+               one:=NewFPint(1)
+               if Q.z.equals(one) {aff=true}
+
+               var A,C *FP
+               B:=NewFPcopy(E.z)
+               D:=NewFPcopy(E.z)
+               if !aff {
+                       A=NewFPcopy(Q.z)
+                       C=NewFPcopy(Q.z)
+
+                       A.sqr(); B.sqr()
+                       C.mul(A); D.mul(B)
+
+                       A.mul(E.x)
+                       C.mul(E.y)
+               } else {
+                       A=NewFPcopy(E.x)
+                       C=NewFPcopy(E.y)
+       
+                       B.sqr()
+                       D.mul(B)
+               }
+
+               B.mul(Q.x); B.sub(A)
+               D.mul(Q.y); D.sub(C)
+
+               if B.iszilch() {
+                       if D.iszilch() {
+                               E.dbl()
+                               return
+                       } else {
+                               E.INF=true
+                               return
+                       }
+               }
+
+               if !aff {E.z.mul(Q.z)}
+               E.z.mul(B)
+
+               e:=NewFPcopy(B); e.sqr()
+               B.mul(e)
+               A.mul(e)
+
+               e.copy(A)
+               e.add(A); e.add(B)
+               E.x.copy(D); E.x.sqr(); E.x.sub(e);
+
+               A.sub(E.x);
+               E.y.copy(A); E.y.mul(D)
+               C.mul(B); E.y.sub(C)
+
+               //      x.reduce();
+               //      y.reduce();
+               //      z.reduce();
+               E.x.norm()
+               E.y.norm()
+               E.z.norm()
+       }
+       if CURVETYPE==EDWARDS {
+               b:=NewFPbig(NewBIGints(CURVE_B))
+               A:=NewFPcopy(E.z)
+               B:=NewFPint(0)
+               C:=NewFPcopy(E.x)
+               D:=NewFPcopy(E.y)
+               EE:=NewFPint(0)
+               F:=NewFPint(0)
+               G:=NewFPint(0)
+               //H:=NewFPint(0)
+               //I:=NewFPint(0)
+       
+               A.mul(Q.z);
+               B.copy(A); B.sqr()
+               C.mul(Q.x)
+               D.mul(Q.y)
+
+               EE.copy(C); EE.mul(D); EE.mul(b)
+               F.copy(B); F.sub(EE)
+               G.copy(B); G.add(EE)
+
+               if CURVE_A==1 {
+                       EE.copy(D); EE.sub(C)
+               }
+               C.add(D)
+
+               B.copy(E.x); B.add(E.y)
+               D.copy(Q.x); D.add(Q.y)
+               B.mul(D)
+               B.sub(C)
+               B.mul(F)
+               E.x.copy(A); E.x.mul(B)
+
+               if CURVE_A==1 {
+                       C.copy(EE); C.mul(G)
+               }
+               if CURVE_A==-1 {
+                       C.mul(G)
+               }
+               E.y.copy(A); E.y.mul(C)
+               E.z.copy(F); E.z.mul(G)
+               //      x.reduce(); y.reduce(); z.reduce();
+               E.x.norm(); E.y.norm(); E.z.norm()
+       }
+       return
+}
+
+/* Differential Add for Montgomery curves. this+=Q where W is this-Q and is 
affine. */
+func (E *ECP) dadd(Q *ECP,W *ECP) {
+       A:=NewFPcopy(E.x)
+       B:=NewFPcopy(E.x)
+       C:=NewFPcopy(Q.x)
+       D:=NewFPcopy(Q.x)
+       DA:=NewFPint(0)
+       CB:=NewFPint(0)
+                       
+       A.add(E.z)
+       B.sub(E.z)
+
+       C.add(Q.z)
+       D.sub(Q.z)
+
+       DA.copy(D); DA.mul(A)
+       CB.copy(C); CB.mul(B)
+
+       A.copy(DA); A.add(CB); A.sqr()
+       B.copy(DA); B.sub(CB); B.sqr()
+
+       E.x.copy(A)
+       E.z.copy(W.x); E.z.mul(B)
+
+       if E.z.iszilch() {
+               E.inf()
+       } else {E.INF=false;}
+
+       //      x.reduce();
+       E.x.norm();
+}
+
+/* this-=Q */
+func (E *ECP) sub(Q *ECP) {
+       Q.neg()
+       E.add(Q)
+       Q.neg()
+}
+
+func multiaffine(m int,P []*ECP) {
+       t1:=NewFPint(0)
+       t2:=NewFPint(0)
+
+       var work []*FP
+
+       for i:=0;i<m;i++ {
+               work=append(work,NewFPint(0))
+       }
+       
+       work[0].one()
+       work[1].copy(P[0].z)
+
+       for i:=2;i<m;i++ {
+               work[i].copy(work[i-1])
+               work[i].mul(P[i-1].z)
+       }
+
+       t1.copy(work[m-1])
+       t1.mul(P[m-1].z)
+       t1.inverse()
+       t2.copy(P[m-1].z)
+       work[m-1].mul(t1)
+
+       for i:=m-2;;i-- {
+               if i==0 {
+                       work[0].copy(t1)
+                       work[0].mul(t2)
+                       break
+               }
+               work[i].mul(t2)
+               work[i].mul(t1)
+               t2.mul(P[i].z)
+       }
+/* now work[] contains inverses of all Z coordinates */
+
+       for i:=0;i<m;i++ {
+               P[i].z.one()
+               t1.copy(work[i])
+               t1.sqr()
+               P[i].x.mul(t1)
+               t1.mul(work[i])
+               P[i].y.mul(t1)
+       }    
+}
+
+/* constant time multiply by small integer of length bts - use ladder */
+func (E *ECP) pinmul(e int32,bts int32) *ECP { 
+       if CURVETYPE==MONTGOMERY {
+               return E.mul(NewBIGint(int(e)))
+       } else {
+               P:=NewECP()
+               R0:=NewECP()
+               R1:=NewECP(); R1.copy(E)
+
+               for i:=bts-1;i>=0;i-- {
+                       b:=int((e>>uint32(i))&1)
+                       P.copy(R1)
+                       P.add(R0)
+                       R0.cswap(R1,b)
+                       R1.copy(P)
+                       R0.dbl()
+                       R0.cswap(R1,b)
+               }
+               P.copy(R0)
+               P.affine()
+               return P
+       }
+}
+
+/* return e.this */
+
+func (E *ECP) mul(e *BIG) *ECP {
+       if (e.iszilch() || E.is_infinity()) {return NewECP()}
+       P:=NewECP()
+       if CURVETYPE==MONTGOMERY {
+/* use Ladder */
+               D:=NewECP();
+               R0:=NewECP(); R0.copy(E)
+               R1:=NewECP(); R1.copy(E)
+               R1.dbl()
+               D.copy(E); D.affine()
+               nb:=e.nbits()
+               for i:=nb-2;i>=0;i-- {
+                       b:=int(e.bit(i))
+                       P.copy(R1)
+                       P.dadd(R0,D)
+                       R0.cswap(R1,b)
+                       R1.copy(P)
+                       R0.dbl()
+                       R0.cswap(R1,b)
+               }
+               P.copy(R0)
+       } else {
+// fixed size windows 
+               mt:=NewBIG()
+               t:=NewBIG()
+               Q:=NewECP()
+               C:=NewECP()
+
+               var W []*ECP
+               var w [1+(NLEN*int(BASEBITS)+3)/4]int8
+
+               E.affine();
+
+               Q.copy(E);
+               Q.dbl();
+
+               W=append(W,NewECP());
+               W[0].copy(E);
+
+               for i:=1;i<8;i++ {
+                       W=append(W,NewECP())
+                       W[i].copy(W[i-1])
+                       W[i].add(Q)
+               }
+
+
+// convert the table to affine 
+               if CURVETYPE==WEIERSTRASS {
+                       multiaffine(8,W[:])
+               }
+
+
+// make exponent odd - add 2P if even, P if odd 
+               t.copy(e)
+               s:=int(t.parity())
+               t.inc(1); t.norm(); ns:=int(t.parity()); mt.copy(t); mt.inc(1); 
mt.norm()
+               t.cmove(mt,s)
+               Q.cmove(E,ns)
+               C.copy(Q)
+
+               nb:=1+(t.nbits()+3)/4
+
+// convert exponent to signed 4-bit window 
+               for i:=0;i<nb;i++ {
+                       w[i]=int8(t.lastbits(5)-16)
+                       t.dec(int(w[i])); t.norm()
+                       t.fshr(4)       
+               }
+               w[nb]=int8(t.lastbits(5))
+
+               P.copy(W[(int(w[nb])-1)/2])  
+               for i:=nb-1;i>=0;i-- {
+                       Q.selector(W,int32(w[i]))
+                       P.dbl()
+                       P.dbl()
+                       P.dbl()
+                       P.dbl()
+                       P.add(Q)
+               }
+               P.sub(C) /* apply correction */
+       }
+       P.affine()
+       return P
+}
+
+/* Return e.this+f.Q */
+
+func (E *ECP) mul2(e *BIG,Q *ECP,f *BIG) *ECP {
+       te:=NewBIG()
+       tf:=NewBIG()
+       mt:=NewBIG()
+       S:=NewECP()
+       T:=NewECP()
+       C:=NewECP()
+       var W [] *ECP
+       //ECP[] W=new ECP[8];
+       var w [1+(NLEN*int(BASEBITS)+1)/2]int8          
+
+       E.affine()
+       Q.affine()
+
+       te.copy(e)
+       tf.copy(f)
+
+// precompute table 
+       for i:=0;i<8;i++ {
+               W=append(W,NewECP())
+       }
+       W[1].copy(E); W[1].sub(Q)
+       W[2].copy(E); W[2].add(Q);
+       S.copy(Q); S.dbl();
+       W[0].copy(W[1]); W[0].sub(S);
+       W[3].copy(W[2]); W[3].add(S);
+       T.copy(E); T.dbl();
+       W[5].copy(W[1]); W[5].add(T);
+       W[6].copy(W[2]); W[6].add(T);
+       W[4].copy(W[5]); W[4].sub(S);
+       W[7].copy(W[6]); W[7].add(S);
+
+// convert the table to affine 
+       if CURVETYPE==WEIERSTRASS { 
+               multiaffine(8,W)
+       }
+
+// if multiplier is odd, add 2, else add 1 to multiplier, and add 2P or P to 
correction 
+
+       s:=int(te.parity());
+       te.inc(1); te.norm(); ns:=int(te.parity()); mt.copy(te); mt.inc(1); 
mt.norm()
+       te.cmove(mt,s)
+       T.cmove(E,ns)
+       C.copy(T)
+
+       s=int(tf.parity())
+       tf.inc(1); tf.norm(); ns=int(tf.parity()); mt.copy(tf); mt.inc(1); 
mt.norm()
+       tf.cmove(mt,s)
+       S.cmove(Q,ns)
+       C.add(S)
+
+       mt.copy(te); mt.add(tf); mt.norm()
+       nb:=1+(mt.nbits()+1)/2
+
+// convert exponent to signed 2-bit window 
+       for i:=0;i<nb;i++ {
+               a:=(te.lastbits(3)-4)
+               te.dec(int(a)); te.norm()
+               te.fshr(2)
+               b:=(tf.lastbits(3)-4)
+               tf.dec(int(b)); tf.norm()
+               tf.fshr(2)
+               w[i]=int8(4*a+b)
+       }
+       w[nb]=int8(4*te.lastbits(3)+tf.lastbits(3))
+       S.copy(W[(w[nb]-1)/2])  
+
+       for i:=nb-1;i>=0;i-- {
+               T.selector(W,int32(w[i]));
+               S.dbl()
+               S.dbl()
+               S.add(T)
+       }
+       S.sub(C) /* apply correction */
+       S.affine()
+       return S
+}
+
+/*
+func main() {
+       Gx:=NewBIGints(CURVE_Gx);
+       var Gy *BIG
+       var P *ECP
+
+       if CURVETYPE!=MONTGOMERY {Gy=NewBIGints(CURVE_Gy)}
+       r:=NewBIGints(CURVE_Order)
+
+       //r.dec(7);
+       
+       fmt.Printf("Gx= "+Gx.toString())
+       fmt.Printf("\n")
+
+       if CURVETYPE!=MONTGOMERY {
+               fmt.Printf("Gy= "+Gy.toString())
+               fmt.Printf("\n")
+       }       
+
+       if CURVETYPE!=MONTGOMERY {
+               P=NewECPbigs(Gx,Gy)
+       } else  {P=NewECPbig(Gx)}
+
+       fmt.Printf("P= "+P.toString());         
+       fmt.Printf("\n")
+
+       R:=P.mul(r);
+               //for (int i=0;i<10000;i++)
+               //      R=P.mul(r);
+       
+       fmt.Printf("R= "+R.toString())
+       fmt.Printf("\n")
+}
+*/
\ No newline at end of file

Reply via email to