github.com/jiajun1992/watercarver@v0.0.0-20191031150618-dfc2b17c0c4a/go-ethereum/ctcrypto/crypto/multiexp.go (about)

     1  package crypto
     2  
     3  import (
     4  	"fmt"
     5  )
     6  
     7  var Identity_p3 ExtendedGroupElement
     8  
     9  type MultiexpData struct {
    10  	Scalar Key
    11  	Point ExtendedGroupElement
    12  }
    13  
    14  func AppendMultiexpData(data *[]MultiexpData, point *Key, scalar *Key) {
    15  	var _point ExtendedGroupElement
    16  	_point.FromBytes(point)
    17  	*data = append(*data, MultiexpData{Point:_point, Scalar:*scalar})
    18  }
    19  
    20  type Straus_cached_data struct {
    21  	Multiples [][]CachedGroupElement
    22  }
    23  
    24  const STRAUS_C = 4
    25  
    26  func lessThan(k0 *Key, k1 *Key) bool {
    27  	for n := 31; n >= 0; n-- {
    28  		if k0[n] < k1[n] {
    29  			return true
    30  		}
    31  		if k0[n] > k1[n] {
    32  			return false
    33  		}
    34  	}
    35  	return false
    36  }
    37  
    38  func pow2(n int) (res *Key) {
    39  	res = new(Key)
    40  	*res = Zero
    41  	res[n >> 3] |= 1 << uint(n & 7)
    42  	return
    43  }
    44  
    45  func test(k Key, n int) int {
    46  	if n >= 256 {
    47  		return 0
    48  	}
    49  	return int(k[n >> 3] & (1 << uint(n & 7)))
    50  }
    51  
    52  func add(p3 *ExtendedGroupElement, other *CachedGroupElement) {
    53  	var p1 CompletedGroupElement
    54  	geAdd(&p1, p3, other)
    55  	p1.ToExtended(p3)
    56  }
    57  
    58  func add3_3(p3 *ExtendedGroupElement, other *ExtendedGroupElement) {
    59  	var cached CachedGroupElement
    60  	other.ToCached(&cached)
    61  	add(p3, &cached)
    62  }
    63  
    64  func straus(data *[]MultiexpData, cache *Straus_cached_data, STEP int) (result Key, err error) {
    65  	if cache != nil && (len(cache.Multiples) < 1 || len(cache.Multiples[1]) < len(*data)) {
    66  		err = fmt.Errorf("Cache is too small ")
    67  		return
    68  	}
    69  	if STEP <= 0 {
    70  		STEP = 192
    71  	}
    72  	local_cache := cache
    73  	if local_cache == nil {
    74  		local_cache, err = straus_init_cache(data, 0)
    75  		if err != nil {
    76  			return
    77  		}
    78  	}
    79  
    80  	var cached CachedGroupElement
    81  	var p1 CompletedGroupElement
    82  
    83  	digits := make([]uint8, 64 * len(*data))
    84  	for j := 0; j < len(*data); j++ {
    85  		bytes := (*data)[j].Scalar[:]
    86  		for i := 0; i < 64; i += 2 {
    87  			digits[j * 64 + i] = bytes[0] & 0xf
    88  			digits[j * 64 + i + 1] = bytes[0] >> 4
    89  			bytes = bytes[1:]
    90  		}
    91  	}
    92  	maxscalar := Zero
    93  	for i := 0; i < len(*data); i++ {
    94  		if lessThan(&maxscalar, &(*data)[i].Scalar) {
    95  			maxscalar = (*data)[i].Scalar
    96  		}
    97  	}
    98  	start_i := 0
    99  	for start_i < 256 && !(lessThan(&maxscalar, pow2(start_i))) {
   100  		start_i += STRAUS_C
   101  	}
   102  
   103  	res_p3 := Identity_p3
   104  
   105  	for start_offset := 0; start_offset < len(*data); start_offset += STEP {
   106  		num_points := len(*data) - start_offset
   107  		if num_points > STEP {
   108  			num_points = STEP
   109  		}
   110  
   111  		band_p3 := Identity_p3
   112  		i := start_i
   113  		skip := false
   114  		if !(i < STRAUS_C) {
   115  			skip = true
   116  		}
   117  		for !(i < STRAUS_C) {
   118  			if !skip {
   119  				var p2 ProjectiveGroupElement
   120  				band_p3.ToProjective(&p2)
   121  				for j:= 0; j < STRAUS_C; j++ {
   122  					p2.Double(&p1)
   123  					if j == STRAUS_C - 1 {
   124  						p1.ToExtended(&band_p3)
   125  					} else {
   126  						p1.ToProjective(&p2)
   127  					}
   128  				}
   129  			}
   130  			i -= STRAUS_C
   131  			for j := start_offset; j < start_offset + num_points; j++ {
   132  				digit := digits[j * 64 + i / 4]
   133  
   134  				if digit != 0 {
   135  					geAdd(&p1, &band_p3, &local_cache.Multiples[digit][j])
   136  					p1.ToExtended(&band_p3)
   137  				}
   138  			}
   139  			skip = false
   140  		}
   141  
   142  		band_p3.ToCached(&cached)
   143  		geAdd(&p1, &res_p3, &cached)
   144  		p1.ToExtended(&res_p3)
   145  	}
   146  
   147  	res_p3.ToBytes(&result)
   148  	return
   149  }
   150  
   151  func straus_init_cache(data *[]MultiexpData, N int) (cache *Straus_cached_data, err error) {
   152  	if N == 0 {
   153  		N = len(*data)
   154  	}
   155  	if N > len(*data) {
   156  		err = fmt.Errorf("Bad cache base data ")
   157  		return
   158  	}
   159  	var p1 CompletedGroupElement
   160  	var p3 ExtendedGroupElement
   161  	cache = new(Straus_cached_data)
   162  	cache.Multiples = make([][]CachedGroupElement, 1 << STRAUS_C)
   163  	offset := 0
   164  	cache.Multiples[1] = make([]CachedGroupElement, N)
   165  	for i := offset; i < N; i++{
   166  		(*data)[i].Point.ToCached(&cache.Multiples[1][i])
   167  	}
   168  	for i := 2; i < (1 << STRAUS_C); i++ {
   169  		cache.Multiples[i] = make([]CachedGroupElement, N)
   170  	}
   171  	for j := offset; j < N; j++ {
   172  		for i := 2; i < (1 << STRAUS_C); i++ {
   173  			geAdd(&p1, &(*data)[j].Point, &cache.Multiples[i-1][j])
   174  			p1.ToExtended(&p3)
   175  			p3.ToCached(&cache.Multiples[i][j])
   176  		}
   177  	}
   178  	return
   179  }
   180  
   181  func pippenger(data *[]MultiexpData, cache *Pippenger_cached_data, cache_size int, c int) (_result Key, err error) {
   182  	if cache != nil && cache_size == 0 {
   183  		cache_size = len(cache.cached)
   184  	}
   185  	if cache != nil && cache_size > len(cache.cached) {
   186  		err = fmt.Errorf("Cache is too small ")
   187  		return
   188  	}
   189  	if c == 0 {
   190  		c = get_pippenger_c(len(*data))
   191  	}
   192  	if c > 9 {
   193  		err = fmt.Errorf("c is too large ")
   194  		return
   195  	}
   196  
   197  	result := Identity_p3
   198  	result_init := false
   199  	buckets := make([]ExtendedGroupElement, 1 << uint(c))
   200  	var buckets_init []bool
   201  	local_cache := cache
   202  	if local_cache == nil {
   203  		local_cache, err = pippenger_init_cache(data, 0, 0)
   204  		if err != nil {
   205  			return
   206  		}
   207  		//cache_size = len(*data)
   208  	}
   209  	var local_cache2 *Pippenger_cached_data
   210  	if len(*data) > cache_size {
   211  		local_cache2, err = pippenger_init_cache(data, cache_size, 0)
   212  		if err != nil {
   213  			return
   214  		}
   215  	}
   216  
   217  	maxscalar := Zero
   218  	for i := 0; i < len(*data); i++ {
   219  		if lessThan(&maxscalar, &(*data)[i].Scalar) {
   220  			maxscalar = (*data)[i].Scalar
   221  		}
   222  	}
   223  	groups := 0
   224  	for groups < 256 && !(lessThan(&maxscalar, pow2(groups))) {
   225  		groups++
   226  	}
   227  	groups = (groups + c - 1) / c
   228  
   229  	for k := groups - 1; k >= 0; k-- {
   230  		if result_init {
   231  			var p2 ProjectiveGroupElement
   232  			result.ToProjective(&p2)
   233  			for i := 0; i < c; i++ {
   234  				var p1 CompletedGroupElement
   235  				p2.Double(&p1)
   236  				if i == c - 1 {
   237  					p1.ToExtended(&result)
   238  				} else {
   239  					p1.ToProjective(&p2)
   240  				}
   241  			}
   242  		}
   243  		buckets_init = make([]bool, 1 << uint(c))
   244  
   245  		for i := 0; i < len(*data); i++ {
   246  			bucket := 0
   247  			for j := 0; j < c; j++ {
   248  				if test((*data)[i].Scalar, k * c + j) != 0 {
   249  					bucket |= 1 << uint(j)
   250  				}
   251  			}
   252  			if bucket == 0 {
   253  				continue
   254  			}
   255  			if bucket >= (1 << uint(c)) {
   256  				err = fmt.Errorf("bucket overflow")
   257  				return
   258  			}
   259  			if buckets_init[bucket] {
   260  				if i < cache_size {
   261  					add(&buckets[bucket], &local_cache.cached[i])
   262  				} else {
   263  					add(&buckets[bucket], &local_cache2.cached[i - cache_size])
   264  				}
   265  			} else {
   266  				buckets[bucket] = (*data)[i].Point
   267  				buckets_init[bucket] = true
   268  			}
   269  		}
   270  
   271  		var pail ExtendedGroupElement
   272  		pail_init := false
   273  		for i := (1 << uint(c)) - 1; i > 0; i-- {
   274  			if buckets_init[i] {
   275  				if pail_init {
   276  					add3_3(&pail, &buckets[i])
   277  				} else {
   278  					pail = buckets[i]
   279  					pail_init = true
   280  				}
   281  			}
   282  			if pail_init {
   283  				if result_init {
   284  					add3_3(&result, &pail)
   285  				} else {
   286  					result = pail
   287  					result_init = true
   288  				}
   289  			}
   290  			/*
   291  			var tmp Key
   292  			pail.ToBytes(&tmp)
   293  			fmt.Printf("k: %d i:%d pail:%s ", k, i, tmp)
   294  			result.ToBytes(&tmp)
   295  			fmt.Printf("result:%s\n", tmp)
   296  			*/
   297  		}
   298  	}
   299  
   300  	result.ToBytes(&_result)
   301  	return
   302  }
   303  
   304  func get_pippenger_c(N int) int {
   305  	if N <= 13 {
   306  		return 2
   307  	}
   308  	if N <= 29 {
   309  		return 3
   310  	}
   311  	if N <= 83 {
   312  		return 4
   313  	}
   314  	if N <= 185 {
   315  		return 5
   316  	}
   317  	if N <= 465 {
   318  		return 6
   319  	}
   320  	if N <= 1180 {
   321  		return 7
   322  	}
   323  	if N <= 2295 {
   324  		return 8
   325  	}
   326  	return 9
   327  }
   328  
   329  type Pippenger_cached_data struct {
   330  	cached []CachedGroupElement
   331  }
   332  
   333  func pippenger_init_cache(data *[]MultiexpData, start_offset int, N int) (cache *Pippenger_cached_data, err error)  {
   334  	if start_offset > len(*data) {
   335  		err = fmt.Errorf("Bad cache base data ")
   336  		return
   337  	}
   338  	if N == 0 {
   339  		N = len(*data) - start_offset
   340  	}
   341  	if N > len(*data) - start_offset {
   342  		err = fmt.Errorf("Bad cache base data ")
   343  		return
   344  	}
   345  
   346  	cache = new(Pippenger_cached_data)
   347  
   348  	cache.cached = make([]CachedGroupElement, N)
   349  	for i := 0; i < N; i++ {
   350  		(*data)[i + start_offset].Point.ToCached(&cache.cached[i])
   351  	}
   352  	return
   353  }
   354  
   355  func Multiexp(data *[]MultiexpData, HiGi_size int) (Key, error) {
   356  	if HiGi_size > 0 {
   357  		if HiGi_size <= 232 && len(*data) == HiGi_size {
   358  			return straus(data, straus_HiGi_cache, 0)
   359  		} else {
   360  			return pippenger(data, pippenger_HiGi_cache, HiGi_size, get_pippenger_c(len(*data)))
   361  		}
   362  	} else {
   363  		if len(*data) <= 95 {
   364  			return straus(data, nil, 0)
   365  		} else {
   366  			return pippenger(data, nil, 0, get_pippenger_c(len(*data)))
   367  		}
   368  	}
   369  }
   370  
   371  const STRAUS_SIZE_LIMIT = 232
   372  const PIPPENGER_SIZE_LIMIT = 0
   373  var straus_HiGi_cache *Straus_cached_data
   374  var pippenger_HiGi_cache *Pippenger_cached_data
   375  
   376  func InitCache(data []MultiexpData) {
   377  	Identity_p3.FromBytes(&Identity)
   378  	pstraus_HiGi_cache, err := straus_init_cache(&data, STRAUS_SIZE_LIMIT)
   379  	if err != nil {
   380  		panic("fail to init cache for multiexp ")
   381  	}
   382  	ppippenger_HiGi_cache, err := pippenger_init_cache(&data, 0, PIPPENGER_SIZE_LIMIT)
   383  	if err != nil {
   384  		panic("fail to init cache for multiexp ")
   385  	}
   386  	straus_HiGi_cache = pstraus_HiGi_cache
   387  	pippenger_HiGi_cache = ppippenger_HiGi_cache
   388  }