mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 01:43:47 +00:00
Merge pull request #10 from ethereum/master
Pull latest changes from go-ethereum
This commit is contained in:
commit
5d7dec9799
76 changed files with 3589 additions and 387 deletions
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
|
|
@ -5,5 +5,7 @@ accounts/usbwallet @karalabe
|
|||
consensus @karalabe
|
||||
core/ @karalabe @holiman
|
||||
eth/ @karalabe
|
||||
les/ @zsfelfoldi
|
||||
light/ @zsfelfoldi
|
||||
mobile/ @karalabe
|
||||
p2p/ @fjl @zsfelfoldi
|
||||
|
|
|
|||
17
.github/stale.yml
vendored
Normal file
17
.github/stale.yml
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 366
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 42
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
1.8.2
|
||||
1.8.3
|
||||
|
|
|
|||
|
|
@ -169,6 +169,21 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interf
|
|||
return set(elem, reflectValue, arguments.NonIndexed()[0])
|
||||
}
|
||||
|
||||
// Computes the full size of an array;
|
||||
// i.e. counting nested arrays, which count towards size for unpacking.
|
||||
func getArraySize(arr *Type) int {
|
||||
size := arr.Size
|
||||
// Arrays can be nested, with each element being the same size
|
||||
arr = arr.Elem
|
||||
for arr.T == ArrayTy {
|
||||
// Keep multiplying by elem.Size while the elem is an array.
|
||||
size *= arr.Size
|
||||
arr = arr.Elem
|
||||
}
|
||||
// Now we have the full array size, including its children.
|
||||
return size
|
||||
}
|
||||
|
||||
// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,
|
||||
// without supplying a struct to unpack into. Instead, this method returns a list containing the
|
||||
// values. An atomic argument will be a list with one element.
|
||||
|
|
@ -181,9 +196,14 @@ func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) {
|
|||
// If we have a static array, like [3]uint256, these are coded as
|
||||
// just like uint256,uint256,uint256.
|
||||
// This means that we need to add two 'virtual' arguments when
|
||||
// we count the index from now on
|
||||
|
||||
virtualArgs += arg.Type.Size - 1
|
||||
// we count the index from now on.
|
||||
//
|
||||
// Array values nested multiple levels deep are also encoded inline:
|
||||
// [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256
|
||||
//
|
||||
// Calculate the full array size to get the correct offset for the next argument.
|
||||
// Decrement it by 1, as the normal index increment is still applied.
|
||||
virtualArgs += getArraySize(&arg.Type) - 1
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -164,118 +164,147 @@ var bindType = map[Lang]func(kind abi.Type) string{
|
|||
LangJava: bindTypeJava,
|
||||
}
|
||||
|
||||
// Helper function for the binding generators.
|
||||
// It reads the unmatched characters after the inner type-match,
|
||||
// (since the inner type is a prefix of the total type declaration),
|
||||
// looks for valid arrays (possibly a dynamic one) wrapping the inner type,
|
||||
// and returns the sizes of these arrays.
|
||||
//
|
||||
// Returned array sizes are in the same order as solidity signatures; inner array size first.
|
||||
// Array sizes may also be "", indicating a dynamic array.
|
||||
func wrapArray(stringKind string, innerLen int, innerMapping string) (string, []string) {
|
||||
remainder := stringKind[innerLen:]
|
||||
//find all the sizes
|
||||
matches := regexp.MustCompile(`\[(\d*)\]`).FindAllStringSubmatch(remainder, -1)
|
||||
parts := make([]string, 0, len(matches))
|
||||
for _, match := range matches {
|
||||
//get group 1 from the regex match
|
||||
parts = append(parts, match[1])
|
||||
}
|
||||
return innerMapping, parts
|
||||
}
|
||||
|
||||
// Translates the array sizes to a Go-lang declaration of a (nested) array of the inner type.
|
||||
// Simply returns the inner type if arraySizes is empty.
|
||||
func arrayBindingGo(inner string, arraySizes []string) string {
|
||||
out := ""
|
||||
//prepend all array sizes, from outer (end arraySizes) to inner (start arraySizes)
|
||||
for i := len(arraySizes) - 1; i >= 0; i-- {
|
||||
out += "[" + arraySizes[i] + "]"
|
||||
}
|
||||
out += inner
|
||||
return out
|
||||
}
|
||||
|
||||
// bindTypeGo converts a Solidity type to a Go one. Since there is no clear mapping
|
||||
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
|
||||
// mapped will use an upscaled type (e.g. *big.Int).
|
||||
func bindTypeGo(kind abi.Type) string {
|
||||
stringKind := kind.String()
|
||||
innerLen, innerMapping := bindUnnestedTypeGo(stringKind)
|
||||
return arrayBindingGo(wrapArray(stringKind, innerLen, innerMapping))
|
||||
}
|
||||
|
||||
// The inner function of bindTypeGo, this finds the inner type of stringKind.
|
||||
// (Or just the type itself if it is not an array or slice)
|
||||
// The length of the matched part is returned, with the the translated type.
|
||||
func bindUnnestedTypeGo(stringKind string) (int, string) {
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(stringKind, "address"):
|
||||
parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 2 {
|
||||
return stringKind
|
||||
}
|
||||
return fmt.Sprintf("%scommon.Address", parts[1])
|
||||
return len("address"), "common.Address"
|
||||
|
||||
case strings.HasPrefix(stringKind, "bytes"):
|
||||
parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 3 {
|
||||
return stringKind
|
||||
}
|
||||
return fmt.Sprintf("%s[%s]byte", parts[2], parts[1])
|
||||
parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind)
|
||||
return len(parts[0]), fmt.Sprintf("[%s]byte", parts[1])
|
||||
|
||||
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
|
||||
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 4 {
|
||||
return stringKind
|
||||
}
|
||||
parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind)
|
||||
switch parts[2] {
|
||||
case "8", "16", "32", "64":
|
||||
return fmt.Sprintf("%s%sint%s", parts[3], parts[1], parts[2])
|
||||
return len(parts[0]), fmt.Sprintf("%sint%s", parts[1], parts[2])
|
||||
}
|
||||
return fmt.Sprintf("%s*big.Int", parts[3])
|
||||
return len(parts[0]), "*big.Int"
|
||||
|
||||
case strings.HasPrefix(stringKind, "bool") || strings.HasPrefix(stringKind, "string"):
|
||||
parts := regexp.MustCompile(`([a-z]+)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 3 {
|
||||
return stringKind
|
||||
}
|
||||
return fmt.Sprintf("%s%s", parts[2], parts[1])
|
||||
case strings.HasPrefix(stringKind, "bool"):
|
||||
return len("bool"), "bool"
|
||||
|
||||
case strings.HasPrefix(stringKind, "string"):
|
||||
return len("string"), "string"
|
||||
|
||||
default:
|
||||
return stringKind
|
||||
return len(stringKind), stringKind
|
||||
}
|
||||
}
|
||||
|
||||
// Translates the array sizes to a Java declaration of a (nested) array of the inner type.
|
||||
// Simply returns the inner type if arraySizes is empty.
|
||||
func arrayBindingJava(inner string, arraySizes []string) string {
|
||||
// Java array type declarations do not include the length.
|
||||
return inner + strings.Repeat("[]", len(arraySizes))
|
||||
}
|
||||
|
||||
// bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping
|
||||
// from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly
|
||||
// mapped will use an upscaled type (e.g. BigDecimal).
|
||||
func bindTypeJava(kind abi.Type) string {
|
||||
stringKind := kind.String()
|
||||
innerLen, innerMapping := bindUnnestedTypeJava(stringKind)
|
||||
return arrayBindingJava(wrapArray(stringKind, innerLen, innerMapping))
|
||||
}
|
||||
|
||||
// The inner function of bindTypeJava, this finds the inner type of stringKind.
|
||||
// (Or just the type itself if it is not an array or slice)
|
||||
// The length of the matched part is returned, with the the translated type.
|
||||
func bindUnnestedTypeJava(stringKind string) (int, string) {
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(stringKind, "address"):
|
||||
parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 2 {
|
||||
return stringKind
|
||||
return len(stringKind), stringKind
|
||||
}
|
||||
if parts[1] == "" {
|
||||
return fmt.Sprintf("Address")
|
||||
return len("address"), "Address"
|
||||
}
|
||||
return fmt.Sprintf("Addresses")
|
||||
return len(parts[0]), "Addresses"
|
||||
|
||||
case strings.HasPrefix(stringKind, "bytes"):
|
||||
parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 3 {
|
||||
return stringKind
|
||||
parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 2 {
|
||||
return len(stringKind), stringKind
|
||||
}
|
||||
if parts[2] != "" {
|
||||
return "byte[][]"
|
||||
}
|
||||
return "byte[]"
|
||||
return len(parts[0]), "byte[]"
|
||||
|
||||
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
|
||||
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 4 {
|
||||
return stringKind
|
||||
//Note that uint and int (without digits) are also matched,
|
||||
// these are size 256, and will translate to BigInt (the default).
|
||||
parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 3 {
|
||||
return len(stringKind), stringKind
|
||||
}
|
||||
switch parts[2] {
|
||||
case "8", "16", "32", "64":
|
||||
if parts[1] == "" {
|
||||
if parts[3] == "" {
|
||||
return fmt.Sprintf("int%s", parts[2])
|
||||
|
||||
namedSize := map[string]string{
|
||||
"8": "byte",
|
||||
"16": "short",
|
||||
"32": "int",
|
||||
"64": "long",
|
||||
}[parts[2]]
|
||||
|
||||
//default to BigInt
|
||||
if namedSize == "" {
|
||||
namedSize = "BigInt"
|
||||
}
|
||||
return fmt.Sprintf("int%s[]", parts[2])
|
||||
}
|
||||
}
|
||||
if parts[3] == "" {
|
||||
return fmt.Sprintf("BigInt")
|
||||
}
|
||||
return fmt.Sprintf("BigInts")
|
||||
return len(parts[0]), namedSize
|
||||
|
||||
case strings.HasPrefix(stringKind, "bool"):
|
||||
parts := regexp.MustCompile(`bool(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 2 {
|
||||
return stringKind
|
||||
}
|
||||
if parts[1] == "" {
|
||||
return fmt.Sprintf("bool")
|
||||
}
|
||||
return fmt.Sprintf("bool[]")
|
||||
return len("bool"), "boolean"
|
||||
|
||||
case strings.HasPrefix(stringKind, "string"):
|
||||
parts := regexp.MustCompile(`string(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 2 {
|
||||
return stringKind
|
||||
}
|
||||
if parts[1] == "" {
|
||||
return fmt.Sprintf("String")
|
||||
}
|
||||
return fmt.Sprintf("String[]")
|
||||
return len("string"), "String"
|
||||
|
||||
default:
|
||||
return stringKind
|
||||
return len(stringKind), stringKind
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -325,11 +354,13 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
|
|||
return "String"
|
||||
case "string[]":
|
||||
return "Strings"
|
||||
case "bool":
|
||||
case "boolean":
|
||||
return "Bool"
|
||||
case "bool[]":
|
||||
case "boolean[]":
|
||||
return "Bools"
|
||||
case "BigInt":
|
||||
case "BigInt[]":
|
||||
return "BigInts"
|
||||
default:
|
||||
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String())
|
||||
if len(parts) != 4 {
|
||||
return javaKind
|
||||
|
|
@ -344,8 +375,6 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
|
|||
default:
|
||||
return javaKind
|
||||
}
|
||||
default:
|
||||
return javaKind
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -356,8 +385,7 @@ var methodNormalizer = map[Lang]func(string) string{
|
|||
LangJava: decapitalise,
|
||||
}
|
||||
|
||||
// capitalise makes the first character of a string upper case, also removing any
|
||||
// prefixing underscores from the variable names.
|
||||
// capitalise makes a camel-case string which starts with an upper case character.
|
||||
func capitalise(input string) string {
|
||||
for len(input) > 0 && input[0] == '_' {
|
||||
input = input[1:]
|
||||
|
|
@ -365,12 +393,42 @@ func capitalise(input string) string {
|
|||
if len(input) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.ToUpper(input[:1]) + input[1:]
|
||||
return toCamelCase(strings.ToUpper(input[:1]) + input[1:])
|
||||
}
|
||||
|
||||
// decapitalise makes the first character of a string lower case.
|
||||
// decapitalise makes a camel-case string which starts with a lower case character.
|
||||
func decapitalise(input string) string {
|
||||
return strings.ToLower(input[:1]) + input[1:]
|
||||
for len(input) > 0 && input[0] == '_' {
|
||||
input = input[1:]
|
||||
}
|
||||
if len(input) == 0 {
|
||||
return ""
|
||||
}
|
||||
return toCamelCase(strings.ToLower(input[:1]) + input[1:])
|
||||
}
|
||||
|
||||
// toCamelCase converts an under-score string to a camel-case string
|
||||
func toCamelCase(input string) string {
|
||||
toupper := false
|
||||
|
||||
result := ""
|
||||
for k, v := range input {
|
||||
switch {
|
||||
case k == 0:
|
||||
result = strings.ToUpper(string(input[0]))
|
||||
|
||||
case toupper:
|
||||
result += strings.ToUpper(string(v))
|
||||
toupper = false
|
||||
|
||||
case v == '_':
|
||||
toupper = true
|
||||
|
||||
default:
|
||||
result += string(v)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// structured checks whether a list of ABI data types has enough information to
|
||||
|
|
|
|||
|
|
@ -506,6 +506,7 @@ var bindTests = []struct {
|
|||
}
|
||||
`,
|
||||
},
|
||||
// Tests that methods and returns with underscores inside work correctly.
|
||||
{
|
||||
`Underscorer`,
|
||||
`
|
||||
|
|
@ -531,9 +532,12 @@ var bindTests = []struct {
|
|||
function AllPurelyUnderscoredOutput() constant returns (int _, int __) {
|
||||
return (1, 2);
|
||||
}
|
||||
function _under_scored_func() constant returns (int _int) {
|
||||
return 0;
|
||||
}
|
||||
`, `6060604052341561000f57600080fd5b6103498061001e6000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461008857806367e6633d146100b85780639df484851461014d578063af7486ab1461017d578063b564b34d146101ad578063e02ab24d146101dd578063e409ca451461020d575b600080fd5b341561009357600080fd5b61009b61023d565b604051808381526020018281526020019250505060405180910390f35b34156100c357600080fd5b6100cb610252565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156101115780820151818401526020810190506100f6565b50505050905090810190601f16801561013e5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561015857600080fd5b6101606102a0565b604051808381526020018281526020019250505060405180910390f35b341561018857600080fd5b6101906102b5565b604051808381526020018281526020019250505060405180910390f35b34156101b857600080fd5b6101c06102ca565b604051808381526020018281526020019250505060405180910390f35b34156101e857600080fd5b6101f06102df565b604051808381526020018281526020019250505060405180910390f35b341561021857600080fd5b6102206102f4565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600061025c610309565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820c11dcfa136fc7d182ee4d34f0b12d988496228f7e2d02d2b5376d996ca1743d00029`,
|
||||
`[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`,
|
||||
}
|
||||
`, `6060604052341561000f57600080fd5b6103858061001e6000396000f30060606040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461009357806346546dbe146100c357806367e6633d146100ec5780639df4848514610181578063af7486ab146101b1578063b564b34d146101e1578063e02ab24d14610211578063e409ca4514610241575b600080fd5b341561009e57600080fd5b6100a6610271565b604051808381526020018281526020019250505060405180910390f35b34156100ce57600080fd5b6100d6610286565b6040518082815260200191505060405180910390f35b34156100f757600080fd5b6100ff61028e565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561014557808201518184015260208101905061012a565b50505050905090810190601f1680156101725780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561018c57600080fd5b6101946102dc565b604051808381526020018281526020019250505060405180910390f35b34156101bc57600080fd5b6101c46102f1565b604051808381526020018281526020019250505060405180910390f35b34156101ec57600080fd5b6101f4610306565b604051808381526020018281526020019250505060405180910390f35b341561021c57600080fd5b61022461031b565b604051808381526020018281526020019250505060405180910390f35b341561024c57600080fd5b610254610330565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600080905090565b6000610298610345565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820d1a53d9de9d1e3d55cb3dc591900b63c4f1ded79114f7b79b332684840e186a40029`,
|
||||
`[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_under_scored_func","outputs":[{"name":"_int","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`,
|
||||
`
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
|
|
@ -562,6 +566,7 @@ var bindTests = []struct {
|
|||
a, b, _ = underscorer.UpperUpperCollision(nil)
|
||||
a, b, _ = underscorer.PurelyUnderscoredOutput(nil)
|
||||
a, b, _ = underscorer.AllPurelyUnderscoredOutput(nil)
|
||||
a, _ = underscorer.UnderScoredFunc(nil)
|
||||
|
||||
fmt.Println(a, b, err)
|
||||
`,
|
||||
|
|
@ -737,6 +742,73 @@ var bindTests = []struct {
|
|||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
`DeeplyNestedArray`,
|
||||
`
|
||||
contract DeeplyNestedArray {
|
||||
uint64[3][4][5] public deepUint64Array;
|
||||
function storeDeepUintArray(uint64[3][4][5] arr) public {
|
||||
deepUint64Array = arr;
|
||||
}
|
||||
function retrieveDeepArray() public view returns (uint64[3][4][5]) {
|
||||
return deepUint64Array;
|
||||
}
|
||||
}
|
||||
`,
|
||||
`6060604052341561000f57600080fd5b6106438061001e6000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063344248551461005c5780638ed4573a1461011457806398ed1856146101ab575b600080fd5b341561006757600080fd5b610112600480806107800190600580602002604051908101604052809291906000905b828210156101055783826101800201600480602002604051908101604052809291906000905b828210156100f25783826060020160038060200260405190810160405280929190826003602002808284378201915050505050815260200190600101906100b0565b505050508152602001906001019061008a565b5050505091905050610208565b005b341561011f57600080fd5b61012761021d565b604051808260056000925b8184101561019b578284602002015160046000925b8184101561018d5782846020020151600360200280838360005b8381101561017c578082015181840152602081019050610161565b505050509050019260010192610147565b925050509260010192610132565b9250505091505060405180910390f35b34156101b657600080fd5b6101de6004808035906020019091908035906020019091908035906020019091905050610309565b604051808267ffffffffffffffff1667ffffffffffffffff16815260200191505060405180910390f35b80600090600561021992919061035f565b5050565b6102256103b0565b6000600580602002604051908101604052809291906000905b8282101561030057838260040201600480602002604051908101604052809291906000905b828210156102ed578382016003806020026040519081016040528092919082600380156102d9576020028201916000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff16815260200190600801906020826007010492830192600103820291508084116102945790505b505050505081526020019060010190610263565b505050508152602001906001019061023e565b50505050905090565b60008360058110151561031857fe5b600402018260048110151561032957fe5b018160038110151561033757fe5b6004918282040191900660080292509250509054906101000a900467ffffffffffffffff1681565b826005600402810192821561039f579160200282015b8281111561039e5782518290600461038e9291906103df565b5091602001919060040190610375565b5b5090506103ac919061042d565b5090565b610780604051908101604052806005905b6103c9610459565b8152602001906001900390816103c15790505090565b826004810192821561041c579160200282015b8281111561041b5782518290600361040b929190610488565b50916020019190600101906103f2565b5b5090506104299190610536565b5090565b61045691905b8082111561045257600081816104499190610562565b50600401610433565b5090565b90565b610180604051908101604052806004905b6104726105a7565b81526020019060019003908161046a5790505090565b82600380016004900481019282156105255791602002820160005b838211156104ef57835183826101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555092602001926008016020816007010492830192600103026104a3565b80156105235782816101000a81549067ffffffffffffffff02191690556008016020816007010492830192600103026104ef565b505b50905061053291906105d9565b5090565b61055f91905b8082111561055b57600081816105529190610610565b5060010161053c565b5090565b90565b50600081816105719190610610565b50600101600081816105839190610610565b50600101600081816105959190610610565b5060010160006105a59190610610565b565b6060604051908101604052806003905b600067ffffffffffffffff168152602001906001900390816105b75790505090565b61060d91905b8082111561060957600081816101000a81549067ffffffffffffffff0219169055506001016105df565b5090565b90565b50600090555600a165627a7a7230582087e5a43f6965ab6ef7a4ff056ab80ed78fd8c15cff57715a1bf34ec76a93661c0029`,
|
||||
`[{"constant":false,"inputs":[{"name":"arr","type":"uint64[3][4][5]"}],"name":"storeDeepUintArray","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"retrieveDeepArray","outputs":[{"name":"","type":"uint64[3][4][5]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"name":"deepUint64Array","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"}]`,
|
||||
`
|
||||
// Generate a new random account and a funded simulator
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth := bind.NewKeyedTransactor(key)
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
|
||||
|
||||
//deploy the test contract
|
||||
_, _, testContract, err := DeployDeeplyNestedArray(auth, sim)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to deploy test contract: %v", err)
|
||||
}
|
||||
|
||||
// Finish deploy.
|
||||
sim.Commit()
|
||||
|
||||
//Create coordinate-filled array, for testing purposes.
|
||||
testArr := [5][4][3]uint64{}
|
||||
for i := 0; i < 5; i++ {
|
||||
testArr[i] = [4][3]uint64{}
|
||||
for j := 0; j < 4; j++ {
|
||||
testArr[i][j] = [3]uint64{}
|
||||
for k := 0; k < 3; k++ {
|
||||
//pack the coordinates, each array value will be unique, and can be validated easily.
|
||||
testArr[i][j][k] = uint64(i) << 16 | uint64(j) << 8 | uint64(k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := testContract.StoreDeepUintArray(&bind.TransactOpts{
|
||||
From: auth.From,
|
||||
Signer: auth.Signer,
|
||||
}, testArr); err != nil {
|
||||
t.Fatalf("Failed to store nested array in test contract: %v", err)
|
||||
}
|
||||
|
||||
sim.Commit()
|
||||
|
||||
retrievedArr, err := testContract.RetrieveDeepArray(&bind.CallOpts{
|
||||
From: auth.From,
|
||||
Pending: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to retrieve nested array from test contract: %v", err)
|
||||
}
|
||||
|
||||
//quick check to see if contents were copied
|
||||
// (See accounts/abi/unpack_test.go for more extensive testing)
|
||||
if retrievedArr[4][3][2] != testArr[4][3][2] {
|
||||
t.Fatalf("Retrieved value does not match expected value! got: %d, expected: %d. %v", retrievedArr[4][3][2], testArr[4][3][2], err)
|
||||
}
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
// Tests that packages generated by the binder can be successfully compiled and
|
||||
|
|
|
|||
|
|
@ -299,6 +299,11 @@ func TestPack(t *testing.T) {
|
|||
[32]byte{1},
|
||||
common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000"),
|
||||
},
|
||||
{
|
||||
"uint32[2][3][4]",
|
||||
[4][3][2]uint32{{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}, {{13, 14}, {15, 16}, {17, 18}}, {{19, 20}, {21, 22}, {23, 24}}},
|
||||
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018"),
|
||||
},
|
||||
{
|
||||
"address[]",
|
||||
[]common.Address{{1}, {2}},
|
||||
|
|
|
|||
|
|
@ -93,6 +93,17 @@ func readFixedBytes(t Type, word []byte) (interface{}, error) {
|
|||
|
||||
}
|
||||
|
||||
func getFullElemSize(elem *Type) int {
|
||||
//all other should be counted as 32 (slices have pointers to respective elements)
|
||||
size := 32
|
||||
//arrays wrap it, each element being the same size
|
||||
for elem.T == ArrayTy {
|
||||
size *= elem.Size
|
||||
elem = elem.Elem
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// iteratively unpack elements
|
||||
func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
|
||||
if size < 0 {
|
||||
|
|
@ -104,7 +115,6 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
|
|||
|
||||
// this value will become our slice or our array, depending on the type
|
||||
var refSlice reflect.Value
|
||||
slice := output[start : start+size*32]
|
||||
|
||||
if t.T == SliceTy {
|
||||
// declare our slice
|
||||
|
|
@ -116,15 +126,20 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
|
|||
return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage")
|
||||
}
|
||||
|
||||
for i, j := start, 0; j*32 < len(slice); i, j = i+32, j+1 {
|
||||
// this corrects the arrangement so that we get all the underlying array values
|
||||
if t.Elem.T == ArrayTy && j != 0 {
|
||||
i = start + t.Elem.Size*32*j
|
||||
// Arrays have packed elements, resulting in longer unpack steps.
|
||||
// Slices have just 32 bytes per element (pointing to the contents).
|
||||
elemSize := 32
|
||||
if t.T == ArrayTy {
|
||||
elemSize = getFullElemSize(t.Elem)
|
||||
}
|
||||
|
||||
for i, j := start, 0; j < size; i, j = i+elemSize, j+1 {
|
||||
|
||||
inter, err := toGoType(i, *t.Elem, output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// append the item to our reflect slice
|
||||
refSlice.Index(j).Set(reflect.ValueOf(inter))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,6 +189,11 @@ var unpackTests = []unpackTest{
|
|||
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
|
||||
want: [2]uint32{1, 2},
|
||||
},
|
||||
{
|
||||
def: `[{"type": "uint32[2][3][4]"}]`,
|
||||
enc: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018",
|
||||
want: [4][3][2]uint32{{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}, {{13, 14}, {15, 16}, {17, 18}}, {{19, 20}, {21, 22}, {23, 24}}},
|
||||
},
|
||||
{
|
||||
def: `[{"type": "uint64[]"}]`,
|
||||
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
|
||||
|
|
@ -435,6 +440,46 @@ func TestMultiReturnWithArray(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
|
||||
// Similar to TestMultiReturnWithArray, but with a special case in mind:
|
||||
// values of nested static arrays count towards the size as well, and any element following
|
||||
// after such nested array argument should be read with the correct offset,
|
||||
// so that it does not read content from the previous array argument.
|
||||
const definition = `[{"name" : "multi", "outputs": [{"type": "uint64[3][2][4]"}, {"type": "uint64"}]}]`
|
||||
abi, err := JSON(strings.NewReader(definition))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
buff := new(bytes.Buffer)
|
||||
// construct the test array, each 3 char element is joined with 61 '0' chars,
|
||||
// to from the ((3 + 61) * 0.5) = 32 byte elements in the array.
|
||||
buff.Write(common.Hex2Bytes(strings.Join([]string{
|
||||
"", //empty, to apply the 61-char separator to the first element as well.
|
||||
"111", "112", "113", "121", "122", "123",
|
||||
"211", "212", "213", "221", "222", "223",
|
||||
"311", "312", "313", "321", "322", "323",
|
||||
"411", "412", "413", "421", "422", "423",
|
||||
}, "0000000000000000000000000000000000000000000000000000000000000")))
|
||||
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000009876"))
|
||||
|
||||
ret1, ret1Exp := new([4][2][3]uint64), [4][2][3]uint64{
|
||||
{{0x111, 0x112, 0x113}, {0x121, 0x122, 0x123}},
|
||||
{{0x211, 0x212, 0x213}, {0x221, 0x222, 0x223}},
|
||||
{{0x311, 0x312, 0x313}, {0x321, 0x322, 0x323}},
|
||||
{{0x411, 0x412, 0x413}, {0x421, 0x422, 0x423}},
|
||||
}
|
||||
ret2, ret2Exp := new(uint64), uint64(0x9876)
|
||||
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(*ret1, ret1Exp) {
|
||||
t.Error("array result", *ret1, "!= Expected", ret1Exp)
|
||||
}
|
||||
if *ret2 != ret2Exp {
|
||||
t.Error("int result", *ret2, "!= Expected", ret2Exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
const definition = `[
|
||||
{ "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] },
|
||||
|
|
|
|||
|
|
@ -86,10 +86,6 @@ var (
|
|||
Name: "create",
|
||||
Usage: "indicates the action should be create rather than call",
|
||||
}
|
||||
DisableGasMeteringFlag = cli.BoolFlag{
|
||||
Name: "nogasmetering",
|
||||
Usage: "disable gas metering",
|
||||
}
|
||||
GenesisFlag = cli.StringFlag{
|
||||
Name: "prestate",
|
||||
Usage: "JSON file with prestate (genesis) config",
|
||||
|
|
@ -128,7 +124,6 @@ func init() {
|
|||
ValueFlag,
|
||||
DumpFlag,
|
||||
InputFlag,
|
||||
DisableGasMeteringFlag,
|
||||
MemProfileFlag,
|
||||
CPUProfileFlag,
|
||||
StatDumpFlag,
|
||||
|
|
|
|||
|
|
@ -163,7 +163,6 @@ func runCmd(ctx *cli.Context) error {
|
|||
EVMConfig: vm.Config{
|
||||
Tracer: tracer,
|
||||
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name),
|
||||
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -533,9 +533,11 @@ func (f *faucet) loop() {
|
|||
}
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
for {
|
||||
select {
|
||||
case head := <-heads:
|
||||
// Start a goroutine to update the state from head notifications in the background
|
||||
update := make(chan *types.Header)
|
||||
|
||||
go func() {
|
||||
for head := range update {
|
||||
// New chain head arrived, query the current stats and stream to clients
|
||||
var (
|
||||
balance *big.Int
|
||||
|
|
@ -588,6 +590,17 @@ func (f *faucet) loop() {
|
|||
}
|
||||
}
|
||||
f.lock.RUnlock()
|
||||
}
|
||||
}()
|
||||
// Wait for various events and assing to the appropriate background threads
|
||||
for {
|
||||
select {
|
||||
case head := <-heads:
|
||||
// New head arrived, send if for state update if there's none running
|
||||
select {
|
||||
case update <- head:
|
||||
default:
|
||||
}
|
||||
|
||||
case <-f.update:
|
||||
// Pending requests updated, stream to clients
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ const bzzManifestJSON = "application/bzz-manifest+json"
|
|||
func add(ctx *cli.Context) {
|
||||
args := ctx.Args()
|
||||
if len(args) < 3 {
|
||||
utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH> [<content-type>]")
|
||||
utils.Fatalf("Need at least three arguments <MHASH> <path> <HASH> [<content-type>]")
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -69,7 +69,7 @@ func update(ctx *cli.Context) {
|
|||
|
||||
args := ctx.Args()
|
||||
if len(args) < 3 {
|
||||
utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH>")
|
||||
utils.Fatalf("Need at least three arguments <MHASH> <path> <HASH>")
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -101,7 +101,7 @@ func update(ctx *cli.Context) {
|
|||
func remove(ctx *cli.Context) {
|
||||
args := ctx.Args()
|
||||
if len(args) < 2 {
|
||||
utils.Fatalf("Need atleast two arguments <MHASH> <path>")
|
||||
utils.Fatalf("Need at least two arguments <MHASH> <path>")
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -400,7 +400,7 @@ var (
|
|||
RPCVirtualHostsFlag = cli.StringFlag{
|
||||
Name: "rpcvhosts",
|
||||
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
|
||||
Value: "localhost",
|
||||
Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
|
||||
}
|
||||
RPCApiFlag = cli.StringFlag{
|
||||
Name: "rpcapi",
|
||||
|
|
@ -695,8 +695,9 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) {
|
|||
if ctx.GlobalIsSet(RPCApiFlag.Name) {
|
||||
cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
|
||||
}
|
||||
|
||||
if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) {
|
||||
cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
|
||||
}
|
||||
}
|
||||
|
||||
// setWS creates the WebSocket RPC listener interface string from the set
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ package main
|
|||
import (
|
||||
"bufio"
|
||||
"crypto/ecdsa"
|
||||
crand "crypto/rand"
|
||||
"crypto/sha512"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
|
|
@ -48,6 +49,7 @@ import (
|
|||
)
|
||||
|
||||
const quitCommand = "~Q"
|
||||
const entropySize = 32
|
||||
|
||||
// singletons
|
||||
var (
|
||||
|
|
@ -55,6 +57,7 @@ var (
|
|||
shh *whisper.Whisper
|
||||
done chan struct{}
|
||||
mailServer mailserver.WMailServer
|
||||
entropy [entropySize]byte
|
||||
|
||||
input = bufio.NewReader(os.Stdin)
|
||||
)
|
||||
|
|
@ -83,6 +86,7 @@ var (
|
|||
asymmetricMode = flag.Bool("asym", false, "use asymmetric encryption")
|
||||
generateKey = flag.Bool("generatekey", false, "generate and show the private key")
|
||||
fileExMode = flag.Bool("fileexchange", false, "file exchange mode")
|
||||
fileReader = flag.Bool("filereader", false, "load and decrypt messages saved as files, display as plain text")
|
||||
testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics (password, etc.)")
|
||||
echoMode = flag.Bool("echo", false, "echo mode: prints some arguments for diagnostics")
|
||||
|
||||
|
|
@ -106,6 +110,7 @@ func main() {
|
|||
processArgs()
|
||||
initialize()
|
||||
run()
|
||||
shutdown()
|
||||
}
|
||||
|
||||
func processArgs() {
|
||||
|
|
@ -192,6 +197,8 @@ func initialize() {
|
|||
if len(*argIP) == 0 {
|
||||
argIP = scanLineA("Please enter your IP and port (e.g. 127.0.0.1:30348): ")
|
||||
}
|
||||
} else if *fileReader {
|
||||
*bootstrapMode = true
|
||||
} else {
|
||||
if len(*argEnode) == 0 {
|
||||
argEnode = scanLineA("Please enter the peer's enode: ")
|
||||
|
|
@ -200,11 +207,6 @@ func initialize() {
|
|||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
cfg := &whisper.Config{
|
||||
MaxMessageSize: uint32(*argMaxSize),
|
||||
MinimumAcceptedPOW: *argPoW,
|
||||
}
|
||||
|
||||
if *mailServerMode {
|
||||
if len(msPassword) == 0 {
|
||||
msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ")
|
||||
|
|
@ -212,13 +214,14 @@ func initialize() {
|
|||
utils.Fatalf("Failed to read Mail Server password: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg := &whisper.Config{
|
||||
MaxMessageSize: uint32(*argMaxSize),
|
||||
MinimumAcceptedPOW: *argPoW,
|
||||
}
|
||||
|
||||
shh = whisper.New(cfg)
|
||||
shh.RegisterServer(&mailServer)
|
||||
mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW)
|
||||
} else {
|
||||
shh = whisper.New(cfg)
|
||||
}
|
||||
|
||||
if *argPoW != whisper.DefaultMinimumPoW {
|
||||
err := shh.SetMinimumPoW(*argPoW)
|
||||
|
|
@ -261,6 +264,16 @@ func initialize() {
|
|||
maxPeers = 800
|
||||
}
|
||||
|
||||
_, err = crand.Read(entropy[:])
|
||||
if err != nil {
|
||||
utils.Fatalf("crypto/rand failed: %s", err)
|
||||
}
|
||||
|
||||
if *mailServerMode {
|
||||
shh.RegisterServer(&mailServer)
|
||||
mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW)
|
||||
}
|
||||
|
||||
server = &p2p.Server{
|
||||
Config: p2p.Config{
|
||||
PrivateKey: nodeid,
|
||||
|
|
@ -276,10 +289,11 @@ func initialize() {
|
|||
}
|
||||
}
|
||||
|
||||
func startServer() {
|
||||
func startServer() error {
|
||||
err := server.Start()
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to start Whisper peer: %s.", err)
|
||||
fmt.Printf("Failed to start Whisper peer: %s.", err)
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("my public key: %s \n", common.ToHex(crypto.FromECDSAPub(&asymKey.PublicKey)))
|
||||
|
|
@ -295,9 +309,14 @@ func startServer() {
|
|||
configureNode()
|
||||
}
|
||||
|
||||
if !*forwarderMode {
|
||||
if *fileExMode {
|
||||
fmt.Printf("Please type the file name to be send. To quit type: '%s'\n", quitCommand)
|
||||
} else if *fileReader {
|
||||
fmt.Printf("Please type the file name to be decrypted. To quit type: '%s'\n", quitCommand)
|
||||
} else if !*forwarderMode {
|
||||
fmt.Printf("Please type the message. To quit type: '%s'\n", quitCommand)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isKeyValid(k *ecdsa.PublicKey) bool {
|
||||
|
|
@ -411,8 +430,10 @@ func waitForConnection(timeout bool) {
|
|||
}
|
||||
|
||||
func run() {
|
||||
defer mailServer.Close()
|
||||
startServer()
|
||||
err := startServer()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer server.Stop()
|
||||
shh.Start(nil)
|
||||
defer shh.Stop()
|
||||
|
|
@ -425,21 +446,26 @@ func run() {
|
|||
requestExpiredMessagesLoop()
|
||||
} else if *fileExMode {
|
||||
sendFilesLoop()
|
||||
} else if *fileReader {
|
||||
fileReaderLoop()
|
||||
} else {
|
||||
sendLoop()
|
||||
}
|
||||
}
|
||||
|
||||
func shutdown() {
|
||||
close(done)
|
||||
mailServer.Close()
|
||||
}
|
||||
|
||||
func sendLoop() {
|
||||
for {
|
||||
s := scanLine("")
|
||||
if s == quitCommand {
|
||||
fmt.Println("Quit command received")
|
||||
close(done)
|
||||
break
|
||||
return
|
||||
}
|
||||
sendMsg([]byte(s))
|
||||
|
||||
if *asymmetricMode {
|
||||
// print your own message for convenience,
|
||||
// because in asymmetric mode it is impossible to decrypt it
|
||||
|
|
@ -455,13 +481,11 @@ func sendFilesLoop() {
|
|||
s := scanLine("")
|
||||
if s == quitCommand {
|
||||
fmt.Println("Quit command received")
|
||||
close(done)
|
||||
break
|
||||
return
|
||||
}
|
||||
b, err := ioutil.ReadFile(s)
|
||||
if err != nil {
|
||||
fmt.Printf(">>> Error: %s \n", err)
|
||||
continue
|
||||
} else {
|
||||
h := sendMsg(b)
|
||||
if (h == common.Hash{}) {
|
||||
|
|
@ -475,6 +499,38 @@ func sendFilesLoop() {
|
|||
}
|
||||
}
|
||||
|
||||
func fileReaderLoop() {
|
||||
watcher1 := shh.GetFilter(symFilterID)
|
||||
watcher2 := shh.GetFilter(asymFilterID)
|
||||
if watcher1 == nil && watcher2 == nil {
|
||||
fmt.Println("Error: neither symmetric nor asymmetric filter is installed")
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
s := scanLine("")
|
||||
if s == quitCommand {
|
||||
fmt.Println("Quit command received")
|
||||
return
|
||||
}
|
||||
raw, err := ioutil.ReadFile(s)
|
||||
if err != nil {
|
||||
fmt.Printf(">>> Error: %s \n", err)
|
||||
} else {
|
||||
env := whisper.Envelope{Data: raw} // the topic is zero
|
||||
msg := env.Open(watcher1) // force-open envelope regardless of the topic
|
||||
if msg == nil {
|
||||
msg = env.Open(watcher2)
|
||||
}
|
||||
if msg == nil {
|
||||
fmt.Printf(">>> Error: failed to decrypt the message \n")
|
||||
} else {
|
||||
printMessageInfo(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scanLine(prompt string) string {
|
||||
if len(prompt) > 0 {
|
||||
fmt.Print(prompt)
|
||||
|
|
@ -517,6 +573,7 @@ func sendMsg(payload []byte) common.Hash {
|
|||
if err != nil {
|
||||
utils.Fatalf("failed to create new message: %s", err)
|
||||
}
|
||||
|
||||
envelope, err := msg.Wrap(¶ms)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to seal message: %v \n", err)
|
||||
|
|
@ -552,15 +609,17 @@ func messageLoop() {
|
|||
m2 := af.Retrieve()
|
||||
messages := append(m1, m2...)
|
||||
for _, msg := range messages {
|
||||
reportedOnce := false
|
||||
if !*fileExMode && len(msg.Payload) <= 2048 {
|
||||
printMessageInfo(msg)
|
||||
reportedOnce = true
|
||||
}
|
||||
|
||||
// All messages are saved upon specifying argSaveDir.
|
||||
// fileExMode only specifies how messages are displayed on the console after they are saved.
|
||||
// if fileExMode == true, only the hashes are displayed, since messages might be too big.
|
||||
if len(*argSaveDir) > 0 {
|
||||
writeMessageToFile(*argSaveDir, msg)
|
||||
}
|
||||
|
||||
if !*fileExMode && len(msg.Payload) <= 2048 {
|
||||
printMessageInfo(msg)
|
||||
writeMessageToFile(*argSaveDir, msg, !reportedOnce)
|
||||
}
|
||||
}
|
||||
case <-done:
|
||||
|
|
@ -585,7 +644,11 @@ func printMessageInfo(msg *whisper.ReceivedMessage) {
|
|||
}
|
||||
}
|
||||
|
||||
func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
||||
func writeMessageToFile(dir string, msg *whisper.ReceivedMessage, show bool) {
|
||||
if len(dir) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
timestamp := fmt.Sprintf("%d", msg.Sent)
|
||||
name := fmt.Sprintf("%x", msg.EnvelopeHash)
|
||||
|
||||
|
|
@ -594,30 +657,32 @@ func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
|||
address = crypto.PubkeyToAddress(*msg.Src)
|
||||
}
|
||||
|
||||
env := shh.GetEnvelope(msg.EnvelopeHash)
|
||||
if env == nil {
|
||||
fmt.Printf("\nUnexpected error: envelope not found: %x\n", msg.EnvelopeHash)
|
||||
return
|
||||
}
|
||||
|
||||
// this is a sample code; uncomment if you don't want to save your own messages.
|
||||
//if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
||||
// fmt.Printf("\n%s <%x>: message from myself received, not saved: '%s'\n", timestamp, address, name)
|
||||
// return
|
||||
//}
|
||||
|
||||
if len(dir) > 0 {
|
||||
fullpath := filepath.Join(dir, name)
|
||||
err := ioutil.WriteFile(fullpath, msg.Raw, 0644)
|
||||
err := ioutil.WriteFile(fullpath, env.Data, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
||||
} else {
|
||||
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(msg.Raw))
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("\n%s {%x}: message received (%d bytes), but not saved: %s\n", timestamp, address, len(msg.Raw), name)
|
||||
} else if show {
|
||||
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(env.Data))
|
||||
}
|
||||
}
|
||||
|
||||
func requestExpiredMessagesLoop() {
|
||||
var key, peerID []byte
|
||||
var key, peerID, bloom []byte
|
||||
var timeLow, timeUpp uint32
|
||||
var t string
|
||||
var xt, empty whisper.TopicType
|
||||
var xt whisper.TopicType
|
||||
|
||||
keyID, err := shh.AddSymKeyFromPassword(msPassword)
|
||||
if err != nil {
|
||||
|
|
@ -633,25 +698,31 @@ func requestExpiredMessagesLoop() {
|
|||
for {
|
||||
timeLow = scanUint("Please enter the lower limit of the time range (unix timestamp): ")
|
||||
timeUpp = scanUint("Please enter the upper limit of the time range (unix timestamp): ")
|
||||
t = scanLine("Please enter the topic (hexadecimal): ")
|
||||
if len(t) >= whisper.TopicLength*2 {
|
||||
t = scanLine("Enter the topic (hex). Press enter to request all messages, regardless of the topic: ")
|
||||
if len(t) == whisper.TopicLength*2 {
|
||||
x, err := hex.DecodeString(t)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to parse the topic: %s", err)
|
||||
fmt.Printf("Failed to parse the topic: %s \n", err)
|
||||
continue
|
||||
}
|
||||
xt = whisper.BytesToTopic(x)
|
||||
bloom = whisper.TopicToBloom(xt)
|
||||
obfuscateBloom(bloom)
|
||||
} else if len(t) == 0 {
|
||||
bloom = whisper.MakeFullNodeBloom()
|
||||
} else {
|
||||
fmt.Println("Error: topic is invalid, request aborted")
|
||||
continue
|
||||
}
|
||||
|
||||
if timeUpp == 0 {
|
||||
timeUpp = 0xFFFFFFFF
|
||||
}
|
||||
|
||||
data := make([]byte, 8+whisper.TopicLength)
|
||||
data := make([]byte, 8, 8+whisper.BloomFilterSize)
|
||||
binary.BigEndian.PutUint32(data, timeLow)
|
||||
binary.BigEndian.PutUint32(data[4:], timeUpp)
|
||||
copy(data[8:], xt[:])
|
||||
if xt == empty {
|
||||
data = data[:8]
|
||||
}
|
||||
data = append(data, bloom...)
|
||||
|
||||
var params whisper.MessageParams
|
||||
params.PoW = *argServerPoW
|
||||
|
|
@ -685,3 +756,20 @@ func extractIDFromEnode(s string) []byte {
|
|||
}
|
||||
return n.ID[:]
|
||||
}
|
||||
|
||||
// obfuscateBloom adds 16 random bits to the the bloom
|
||||
// filter, in order to obfuscate the containing topics.
|
||||
// it does so deterministically within every session.
|
||||
// despite additional bits, it will match on average
|
||||
// 32000 times less messages than full node's bloom filter.
|
||||
func obfuscateBloom(bloom []byte) {
|
||||
const half = entropySize / 2
|
||||
for i := 0; i < half; i++ {
|
||||
x := int(entropy[i])
|
||||
if entropy[half+i] < 128 {
|
||||
x += 256
|
||||
}
|
||||
|
||||
bloom[x/8] = 1 << uint(x%8) // set the bit number X
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int {
|
|||
if x.Cmp(params.MinimumDifficulty) < 0 {
|
||||
x.Set(params.MinimumDifficulty)
|
||||
}
|
||||
// calculate a fake block numer for the ice-age delay:
|
||||
// calculate a fake block number for the ice-age delay:
|
||||
// https://github.com/ethereum/EIPs/pull/669
|
||||
// fake_block_number = min(0, block.number - 3_000_000
|
||||
fakeBlockNumber := new(big.Int)
|
||||
|
|
|
|||
|
|
@ -723,10 +723,13 @@ func (bc *BlockChain) Rollback(chain []common.Hash) {
|
|||
}
|
||||
|
||||
// SetReceiptsData computes all the non-consensus fields of the receipts
|
||||
func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) {
|
||||
func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) error {
|
||||
signer := types.MakeSigner(config, block.Number())
|
||||
|
||||
transactions, logIndex := block.Transactions(), uint(0)
|
||||
if len(transactions) != len(receipts) {
|
||||
return errors.New("transaction and receipt count mismatch")
|
||||
}
|
||||
|
||||
for j := 0; j < len(receipts); j++ {
|
||||
// The transaction hash can be retrieved from the transaction itself
|
||||
|
|
@ -754,6 +757,7 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty
|
|||
logIndex++
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertReceiptChain attempts to complete an already existing header chain with
|
||||
|
|
@ -794,7 +798,9 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
|||
continue
|
||||
}
|
||||
// Compute all the non-consensus fields of the receipts
|
||||
SetReceiptsData(bc.chainConfig, block, receipts)
|
||||
if err := SetReceiptsData(bc.chainConfig, block, receipts); err != nil {
|
||||
return i, fmt.Errorf("failed to set receipts data: %v", err)
|
||||
}
|
||||
// Write all the data out into the database
|
||||
if err := WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
||||
return i, fmt.Errorf("failed to write block body: %v", err)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ var (
|
|||
headHeaderKey = []byte("LastHeader")
|
||||
headBlockKey = []byte("LastBlock")
|
||||
headFastKey = []byte("LastFast")
|
||||
trieSyncKey = []byte("TrieSync")
|
||||
|
||||
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`).
|
||||
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
|
||||
|
|
@ -146,6 +147,16 @@ func GetHeadFastBlockHash(db DatabaseReader) common.Hash {
|
|||
return common.BytesToHash(data)
|
||||
}
|
||||
|
||||
// GetTrieSyncProgress retrieves the number of tries nodes fast synced to allow
|
||||
// reportinc correct numbers across restarts.
|
||||
func GetTrieSyncProgress(db DatabaseReader) uint64 {
|
||||
data, _ := db.Get(trieSyncKey)
|
||||
if len(data) == 0 {
|
||||
return 0
|
||||
}
|
||||
return new(big.Int).SetBytes(data).Uint64()
|
||||
}
|
||||
|
||||
// GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil
|
||||
// if the header's not found.
|
||||
func GetHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
||||
|
|
@ -374,6 +385,15 @@ func WriteHeadFastBlockHash(db ethdb.Putter, hash common.Hash) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// WriteTrieSyncProgress stores the fast sync trie process counter to support
|
||||
// retrieving it across restarts.
|
||||
func WriteTrieSyncProgress(db ethdb.Putter, count uint64) error {
|
||||
if err := db.Put(trieSyncKey, new(big.Int).SetUint64(count).Bytes()); err != nil {
|
||||
log.Crit("Failed to store fast sync trie progress", "err", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteHeader serializes a block header into the database.
|
||||
func WriteHeader(db ethdb.Putter, header *types.Header) error {
|
||||
data, err := rlp.EncodeToBytes(header)
|
||||
|
|
|
|||
|
|
@ -877,16 +877,15 @@ func (pool *TxPool) removeTx(hash common.Hash) {
|
|||
// Remove the transaction from the pending lists and reset the account nonce
|
||||
if pending := pool.pending[addr]; pending != nil {
|
||||
if removed, invalids := pending.Remove(tx); removed {
|
||||
// If no more transactions are left, remove the list
|
||||
// If no more pending transactions are left, remove the list
|
||||
if pending.Empty() {
|
||||
delete(pool.pending, addr)
|
||||
delete(pool.beats, addr)
|
||||
} else {
|
||||
// Otherwise postpone any invalidated transactions
|
||||
}
|
||||
// Postpone any invalidated transactions
|
||||
for _, tx := range invalids {
|
||||
pool.enqueueTx(tx.Hash(), tx)
|
||||
}
|
||||
}
|
||||
// Update the account nonce if needed
|
||||
if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce {
|
||||
pool.pendingState.SetNonce(addr, nonce)
|
||||
|
|
|
|||
|
|
@ -557,74 +557,112 @@ func TestTransactionDropping(t *testing.T) {
|
|||
func TestTransactionPostponing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create a test account and fund it
|
||||
pool, key := setupTxPool()
|
||||
// Create the pool to test the postponing with
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
|
||||
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||
|
||||
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
||||
defer pool.Stop()
|
||||
|
||||
account, _ := deriveSender(transaction(0, 0, key))
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000))
|
||||
// Create two test accounts to produce different gap profiles with
|
||||
keys := make([]*ecdsa.PrivateKey, 2)
|
||||
accs := make([]common.Address, len(keys))
|
||||
|
||||
// Add a batch consecutive pending transactions for validation
|
||||
txns := []*types.Transaction{}
|
||||
for i := 0; i < 100; i++ {
|
||||
var tx *types.Transaction
|
||||
if i%2 == 0 {
|
||||
tx = transaction(uint64(i), 100, key)
|
||||
} else {
|
||||
tx = transaction(uint64(i), 500, key)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
accs[i] = crypto.PubkeyToAddress(keys[i].PublicKey)
|
||||
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(50100))
|
||||
}
|
||||
// Add a batch consecutive pending transactions for validation
|
||||
txs := []*types.Transaction{}
|
||||
for i, key := range keys {
|
||||
|
||||
for j := 0; j < 100; j++ {
|
||||
var tx *types.Transaction
|
||||
if (i+j)%2 == 0 {
|
||||
tx = transaction(uint64(j), 25000, key)
|
||||
} else {
|
||||
tx = transaction(uint64(j), 50000, key)
|
||||
}
|
||||
txs = append(txs, tx)
|
||||
}
|
||||
}
|
||||
for i, err := range pool.AddRemotes(txs) {
|
||||
if err != nil {
|
||||
t.Fatalf("tx %d: failed to add transactions: %v", i, err)
|
||||
}
|
||||
pool.promoteTx(account, tx.Hash(), tx)
|
||||
txns = append(txns, tx)
|
||||
}
|
||||
// Check that pre and post validations leave the pool as is
|
||||
if pool.pending[account].Len() != len(txns) {
|
||||
t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns))
|
||||
if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) {
|
||||
t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs))
|
||||
}
|
||||
if len(pool.queue) != 0 {
|
||||
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 0)
|
||||
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
|
||||
}
|
||||
if len(pool.all) != len(txns) {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns))
|
||||
if len(pool.all) != len(txs) {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs))
|
||||
}
|
||||
pool.lockedReset(nil, nil)
|
||||
if pool.pending[account].Len() != len(txns) {
|
||||
t.Errorf("pending transaction mismatch: have %d, want %d", pool.pending[account].Len(), len(txns))
|
||||
if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) {
|
||||
t.Errorf("pending transaction mismatch: have %d, want %d", pending, len(txs))
|
||||
}
|
||||
if len(pool.queue) != 0 {
|
||||
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 0)
|
||||
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
|
||||
}
|
||||
if len(pool.all) != len(txns) {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns))
|
||||
if len(pool.all) != len(txs) {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs))
|
||||
}
|
||||
// Reduce the balance of the account, and check that transactions are reorganised
|
||||
pool.currentState.AddBalance(account, big.NewInt(-750))
|
||||
for _, addr := range accs {
|
||||
pool.currentState.AddBalance(addr, big.NewInt(-1))
|
||||
}
|
||||
pool.lockedReset(nil, nil)
|
||||
|
||||
if _, ok := pool.pending[account].txs.items[txns[0].Nonce()]; !ok {
|
||||
t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txns[0])
|
||||
// The first account's first transaction remains valid, check that subsequent
|
||||
// ones are either filtered out, or queued up for later.
|
||||
if _, ok := pool.pending[accs[0]].txs.items[txs[0].Nonce()]; !ok {
|
||||
t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txs[0])
|
||||
}
|
||||
if _, ok := pool.queue[account].txs.items[txns[0].Nonce()]; ok {
|
||||
t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txns[0])
|
||||
if _, ok := pool.queue[accs[0]].txs.items[txs[0].Nonce()]; ok {
|
||||
t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txs[0])
|
||||
}
|
||||
for i, tx := range txns[1:] {
|
||||
for i, tx := range txs[1:100] {
|
||||
if i%2 == 1 {
|
||||
if _, ok := pool.pending[account].txs.items[tx.Nonce()]; ok {
|
||||
if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok {
|
||||
t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx)
|
||||
}
|
||||
if _, ok := pool.queue[account].txs.items[tx.Nonce()]; !ok {
|
||||
if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; !ok {
|
||||
t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx)
|
||||
}
|
||||
} else {
|
||||
if _, ok := pool.pending[account].txs.items[tx.Nonce()]; ok {
|
||||
if _, ok := pool.pending[accs[0]].txs.items[tx.Nonce()]; ok {
|
||||
t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx)
|
||||
}
|
||||
if _, ok := pool.queue[account].txs.items[tx.Nonce()]; ok {
|
||||
if _, ok := pool.queue[accs[0]].txs.items[tx.Nonce()]; ok {
|
||||
t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(pool.all) != len(txns)/2 {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txns)/2)
|
||||
// The second account's first transaction got invalid, check that all transactions
|
||||
// are either filtered out, or queued up for later.
|
||||
if pool.pending[accs[1]] != nil {
|
||||
t.Errorf("invalidated account still has pending transactions")
|
||||
}
|
||||
for i, tx := range txs[100:] {
|
||||
if i%2 == 1 {
|
||||
if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; !ok {
|
||||
t.Errorf("tx %d: valid but future transaction missing from future queue: %v", 100+i, tx)
|
||||
}
|
||||
} else {
|
||||
if _, ok := pool.queue[accs[1]].txs.items[tx.Nonce()]; ok {
|
||||
t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", 100+i, tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(pool.all) != len(txs)/2 {
|
||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs)/2)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -949,11 +987,11 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
|
|||
account2, _ := deriveSender(transaction(0, 0, key2))
|
||||
pool2.currentState.AddBalance(account2, big.NewInt(1000000))
|
||||
|
||||
txns := []*types.Transaction{}
|
||||
txs := []*types.Transaction{}
|
||||
for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ {
|
||||
txns = append(txns, transaction(origin+i, 100000, key2))
|
||||
txs = append(txs, transaction(origin+i, 100000, key2))
|
||||
}
|
||||
pool2.AddRemotes(txns)
|
||||
pool2.AddRemotes(txs)
|
||||
|
||||
// Ensure the batch optimization honors the same pool mechanics
|
||||
if len(pool1.pending) != len(pool2.pending) {
|
||||
|
|
@ -1124,7 +1162,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
|||
defer sub.Unsubscribe()
|
||||
|
||||
// Create a number of test accounts and fund them
|
||||
keys := make([]*ecdsa.PrivateKey, 3)
|
||||
keys := make([]*ecdsa.PrivateKey, 4)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
|
|
@ -1136,24 +1174,28 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
|||
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0]))
|
||||
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0]))
|
||||
|
||||
txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[1]))
|
||||
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[1]))
|
||||
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[1]))
|
||||
txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[1]))
|
||||
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[1]))
|
||||
|
||||
ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[2])
|
||||
txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[2]))
|
||||
txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2]))
|
||||
txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[2]))
|
||||
|
||||
ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[3])
|
||||
|
||||
// Import the batch and that both pending and queued transactions match up
|
||||
pool.AddRemotes(txs)
|
||||
pool.AddLocal(ltx)
|
||||
|
||||
pending, queued := pool.Stats()
|
||||
if pending != 4 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 4)
|
||||
if pending != 7 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 7)
|
||||
}
|
||||
if queued != 3 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
|
||||
}
|
||||
if err := validateEvents(events, 4); err != nil {
|
||||
if err := validateEvents(events, 7); err != nil {
|
||||
t.Fatalf("original event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
|
|
@ -1166,8 +1208,8 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
|||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
}
|
||||
if queued != 3 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
|
||||
if queued != 5 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 5)
|
||||
}
|
||||
if err := validateEvents(events, 0); err != nil {
|
||||
t.Fatalf("reprice event firing failed: %v", err)
|
||||
|
|
@ -1179,7 +1221,10 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
|||
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); err != ErrUnderpriced {
|
||||
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||
}
|
||||
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced {
|
||||
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced {
|
||||
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||
}
|
||||
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[2])); err != ErrUnderpriced {
|
||||
t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||
}
|
||||
if err := validateEvents(events, 0); err != nil {
|
||||
|
|
@ -1189,7 +1234,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
|||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
// However we can add local underpriced transactions
|
||||
tx := pricedTransaction(1, 100000, big.NewInt(1), keys[2])
|
||||
tx := pricedTransaction(1, 100000, big.NewInt(1), keys[3])
|
||||
if err := pool.AddLocal(tx); err != nil {
|
||||
t.Fatalf("failed to add underpriced local transaction: %v", err)
|
||||
}
|
||||
|
|
@ -1202,6 +1247,22 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
|||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
// And we can fill gaps with properly priced transactions
|
||||
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[0])); err != nil {
|
||||
t.Fatalf("failed to add pending transaction: %v", err)
|
||||
}
|
||||
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(2), keys[1])); err != nil {
|
||||
t.Fatalf("failed to add pending transaction: %v", err)
|
||||
}
|
||||
if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(2), keys[2])); err != nil {
|
||||
t.Fatalf("failed to add queued transaction: %v", err)
|
||||
}
|
||||
if err := validateEvents(events, 5); err != nil {
|
||||
t.Fatalf("post-reprice event firing failed: %v", err)
|
||||
}
|
||||
if err := validateTxPoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that setting the transaction pool gas price to a higher value does not
|
||||
|
|
|
|||
|
|
@ -251,26 +251,12 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) {
|
|||
return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil
|
||||
}
|
||||
|
||||
var (
|
||||
// errNotOnCurve is returned if a point being unmarshalled as a bn256 elliptic
|
||||
// curve point is not on the curve.
|
||||
errNotOnCurve = errors.New("point not on elliptic curve")
|
||||
|
||||
// errInvalidCurvePoint is returned if a point being unmarshalled as a bn256
|
||||
// elliptic curve point is invalid.
|
||||
errInvalidCurvePoint = errors.New("invalid elliptic curve point")
|
||||
)
|
||||
|
||||
// newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point,
|
||||
// returning it, or an error if the point is invalid.
|
||||
func newCurvePoint(blob []byte) (*bn256.G1, error) {
|
||||
p, onCurve := new(bn256.G1).Unmarshal(blob)
|
||||
if !onCurve {
|
||||
return nil, errNotOnCurve
|
||||
}
|
||||
gx, gy, _, _ := p.CurvePoints()
|
||||
if gx.Cmp(bn256.P) >= 0 || gy.Cmp(bn256.P) >= 0 {
|
||||
return nil, errInvalidCurvePoint
|
||||
p := new(bn256.G1)
|
||||
if _, err := p.Unmarshal(blob); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
|
@ -278,14 +264,9 @@ func newCurvePoint(blob []byte) (*bn256.G1, error) {
|
|||
// newTwistPoint unmarshals a binary blob into a bn256 elliptic curve point,
|
||||
// returning it, or an error if the point is invalid.
|
||||
func newTwistPoint(blob []byte) (*bn256.G2, error) {
|
||||
p, onCurve := new(bn256.G2).Unmarshal(blob)
|
||||
if !onCurve {
|
||||
return nil, errNotOnCurve
|
||||
}
|
||||
x2, y2, _, _ := p.CurvePoints()
|
||||
if x2.Real().Cmp(bn256.P) >= 0 || x2.Imag().Cmp(bn256.P) >= 0 ||
|
||||
y2.Real().Cmp(bn256.P) >= 0 || y2.Imag().Cmp(bn256.P) >= 0 {
|
||||
return nil, errInvalidCurvePoint
|
||||
p := new(bn256.G2)
|
||||
if _, err := p.Unmarshal(blob); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,6 @@ type Config struct {
|
|||
// NoRecursion disabled Interpreter call, callcode,
|
||||
// delegate call and create.
|
||||
NoRecursion bool
|
||||
// Disable gas metering
|
||||
DisableGasMetering bool
|
||||
// Enable recording of SHA3/keccak preimages
|
||||
EnablePreimageRecording bool
|
||||
// JumpTable contains the EVM instruction table. This
|
||||
|
|
@ -189,15 +187,12 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er
|
|||
return nil, errGasUintOverflow
|
||||
}
|
||||
}
|
||||
|
||||
if !in.cfg.DisableGasMetering {
|
||||
// consume the gas and return an error if not enough gas is available.
|
||||
// cost is explicitly set so that the capture state defer method cas get the proper cost
|
||||
cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize)
|
||||
if err != nil || !contract.UseGas(cost) {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
}
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
}
|
||||
|
|
|
|||
63
crypto/bn256/bn256_amd64.go
Normal file
63
crypto/bn256/bn256_amd64.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2018 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
|
||||
)
|
||||
|
||||
// G1 is an abstract cyclic group. The zero value is suitable for use as the
|
||||
// output of an operation, but cannot be used as an input.
|
||||
type G1 struct {
|
||||
bn256.G1
|
||||
}
|
||||
|
||||
// Add sets e to a+b and then returns e.
|
||||
func (e *G1) Add(a, b *G1) *G1 {
|
||||
e.G1.Add(&a.G1, &b.G1)
|
||||
return e
|
||||
}
|
||||
|
||||
// ScalarMult sets e to a*k and then returns e.
|
||||
func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
|
||||
e.G1.ScalarMult(&a.G1, k)
|
||||
return e
|
||||
}
|
||||
|
||||
// G2 is an abstract cyclic group. The zero value is suitable for use as the
|
||||
// output of an operation, but cannot be used as an input.
|
||||
type G2 struct {
|
||||
bn256.G2
|
||||
}
|
||||
|
||||
// PairingCheck calculates the Optimal Ate pairing for a set of points.
|
||||
func PairingCheck(a []*G1, b []*G2) bool {
|
||||
as := make([]*bn256.G1, len(a))
|
||||
for i, p := range a {
|
||||
as[i] = &p.G1
|
||||
}
|
||||
bs := make([]*bn256.G2, len(b))
|
||||
for i, p := range b {
|
||||
bs[i] = &p.G2
|
||||
}
|
||||
return bn256.PairingCheck(as, bs)
|
||||
}
|
||||
63
crypto/bn256/bn256_other.go
Normal file
63
crypto/bn256/bn256_other.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2018 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build !amd64 appengine gccgo
|
||||
|
||||
// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto/bn256/google"
|
||||
)
|
||||
|
||||
// G1 is an abstract cyclic group. The zero value is suitable for use as the
|
||||
// output of an operation, but cannot be used as an input.
|
||||
type G1 struct {
|
||||
bn256.G1
|
||||
}
|
||||
|
||||
// Add sets e to a+b and then returns e.
|
||||
func (e *G1) Add(a, b *G1) *G1 {
|
||||
e.G1.Add(&a.G1, &b.G1)
|
||||
return e
|
||||
}
|
||||
|
||||
// ScalarMult sets e to a*k and then returns e.
|
||||
func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
|
||||
e.G1.ScalarMult(&a.G1, k)
|
||||
return e
|
||||
}
|
||||
|
||||
// G2 is an abstract cyclic group. The zero value is suitable for use as the
|
||||
// output of an operation, but cannot be used as an input.
|
||||
type G2 struct {
|
||||
bn256.G2
|
||||
}
|
||||
|
||||
// PairingCheck calculates the Optimal Ate pairing for a set of points.
|
||||
func PairingCheck(a []*G1, b []*G2) bool {
|
||||
as := make([]*bn256.G1, len(a))
|
||||
for i, p := range a {
|
||||
as[i] = &p.G1
|
||||
}
|
||||
bs := make([]*bn256.G2, len(b))
|
||||
for i, p := range b {
|
||||
bs[i] = &p.G2
|
||||
}
|
||||
return bn256.PairingCheck(as, bs)
|
||||
}
|
||||
481
crypto/bn256/cloudflare/bn256.go
Normal file
481
crypto/bn256/cloudflare/bn256.go
Normal file
|
|
@ -0,0 +1,481 @@
|
|||
// Package bn256 implements a particular bilinear group at the 128-bit security
|
||||
// level.
|
||||
//
|
||||
// Bilinear groups are the basis of many of the new cryptographic protocols that
|
||||
// have been proposed over the past decade. They consist of a triplet of groups
|
||||
// (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ
|
||||
// is a generator of the respective group). That function is called a pairing
|
||||
// function.
|
||||
//
|
||||
// This package specifically implements the Optimal Ate pairing over a 256-bit
|
||||
// Barreto-Naehrig curve as described in
|
||||
// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible
|
||||
// with the implementation described in that paper.
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func randomK(r io.Reader) (k *big.Int, err error) {
|
||||
for {
|
||||
k, err = rand.Int(r, Order)
|
||||
if k.Sign() > 0 || err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// G1 is an abstract cyclic group. The zero value is suitable for use as the
|
||||
// output of an operation, but cannot be used as an input.
|
||||
type G1 struct {
|
||||
p *curvePoint
|
||||
}
|
||||
|
||||
// RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r.
|
||||
func RandomG1(r io.Reader) (*big.Int, *G1, error) {
|
||||
k, err := randomK(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return k, new(G1).ScalarBaseMult(k), nil
|
||||
}
|
||||
|
||||
func (g *G1) String() string {
|
||||
return "bn256.G1" + g.p.String()
|
||||
}
|
||||
|
||||
// ScalarBaseMult sets e to g*k where g is the generator of the group and then
|
||||
// returns e.
|
||||
func (e *G1) ScalarBaseMult(k *big.Int) *G1 {
|
||||
if e.p == nil {
|
||||
e.p = &curvePoint{}
|
||||
}
|
||||
e.p.Mul(curveGen, k)
|
||||
return e
|
||||
}
|
||||
|
||||
// ScalarMult sets e to a*k and then returns e.
|
||||
func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
|
||||
if e.p == nil {
|
||||
e.p = &curvePoint{}
|
||||
}
|
||||
e.p.Mul(a.p, k)
|
||||
return e
|
||||
}
|
||||
|
||||
// Add sets e to a+b and then returns e.
|
||||
func (e *G1) Add(a, b *G1) *G1 {
|
||||
if e.p == nil {
|
||||
e.p = &curvePoint{}
|
||||
}
|
||||
e.p.Add(a.p, b.p)
|
||||
return e
|
||||
}
|
||||
|
||||
// Neg sets e to -a and then returns e.
|
||||
func (e *G1) Neg(a *G1) *G1 {
|
||||
if e.p == nil {
|
||||
e.p = &curvePoint{}
|
||||
}
|
||||
e.p.Neg(a.p)
|
||||
return e
|
||||
}
|
||||
|
||||
// Set sets e to a and then returns e.
|
||||
func (e *G1) Set(a *G1) *G1 {
|
||||
if e.p == nil {
|
||||
e.p = &curvePoint{}
|
||||
}
|
||||
e.p.Set(a.p)
|
||||
return e
|
||||
}
|
||||
|
||||
// Marshal converts e to a byte slice.
|
||||
func (e *G1) Marshal() []byte {
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
|
||||
e.p.MakeAffine()
|
||||
ret := make([]byte, numBytes*2)
|
||||
if e.p.IsInfinity() {
|
||||
return ret
|
||||
}
|
||||
temp := &gfP{}
|
||||
|
||||
montDecode(temp, &e.p.x)
|
||||
temp.Marshal(ret)
|
||||
montDecode(temp, &e.p.y)
|
||||
temp.Marshal(ret[numBytes:])
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Unmarshal sets e to the result of converting the output of Marshal back into
|
||||
// a group element and then returns e.
|
||||
func (e *G1) Unmarshal(m []byte) ([]byte, error) {
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
if len(m) < 2*numBytes {
|
||||
return nil, errors.New("bn256: not enough data")
|
||||
}
|
||||
// Unmarshal the points and check their caps
|
||||
if e.p == nil {
|
||||
e.p = &curvePoint{}
|
||||
} else {
|
||||
e.p.x, e.p.y = gfP{0}, gfP{0}
|
||||
}
|
||||
var err error
|
||||
if err = e.p.x.Unmarshal(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.y.Unmarshal(m[numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Encode into Montgomery form and ensure it's on the curve
|
||||
montEncode(&e.p.x, &e.p.x)
|
||||
montEncode(&e.p.y, &e.p.y)
|
||||
|
||||
zero := gfP{0}
|
||||
if e.p.x == zero && e.p.y == zero {
|
||||
// This is the point at infinity.
|
||||
e.p.y = *newGFp(1)
|
||||
e.p.z = gfP{0}
|
||||
e.p.t = gfP{0}
|
||||
} else {
|
||||
e.p.z = *newGFp(1)
|
||||
e.p.t = *newGFp(1)
|
||||
|
||||
if !e.p.IsOnCurve() {
|
||||
return nil, errors.New("bn256: malformed point")
|
||||
}
|
||||
}
|
||||
return m[2*numBytes:], nil
|
||||
}
|
||||
|
||||
// G2 is an abstract cyclic group. The zero value is suitable for use as the
|
||||
// output of an operation, but cannot be used as an input.
|
||||
type G2 struct {
|
||||
p *twistPoint
|
||||
}
|
||||
|
||||
// RandomG2 returns x and g₂ˣ where x is a random, non-zero number read from r.
|
||||
func RandomG2(r io.Reader) (*big.Int, *G2, error) {
|
||||
k, err := randomK(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return k, new(G2).ScalarBaseMult(k), nil
|
||||
}
|
||||
|
||||
func (e *G2) String() string {
|
||||
return "bn256.G2" + e.p.String()
|
||||
}
|
||||
|
||||
// ScalarBaseMult sets e to g*k where g is the generator of the group and then
|
||||
// returns out.
|
||||
func (e *G2) ScalarBaseMult(k *big.Int) *G2 {
|
||||
if e.p == nil {
|
||||
e.p = &twistPoint{}
|
||||
}
|
||||
e.p.Mul(twistGen, k)
|
||||
return e
|
||||
}
|
||||
|
||||
// ScalarMult sets e to a*k and then returns e.
|
||||
func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 {
|
||||
if e.p == nil {
|
||||
e.p = &twistPoint{}
|
||||
}
|
||||
e.p.Mul(a.p, k)
|
||||
return e
|
||||
}
|
||||
|
||||
// Add sets e to a+b and then returns e.
|
||||
func (e *G2) Add(a, b *G2) *G2 {
|
||||
if e.p == nil {
|
||||
e.p = &twistPoint{}
|
||||
}
|
||||
e.p.Add(a.p, b.p)
|
||||
return e
|
||||
}
|
||||
|
||||
// Neg sets e to -a and then returns e.
|
||||
func (e *G2) Neg(a *G2) *G2 {
|
||||
if e.p == nil {
|
||||
e.p = &twistPoint{}
|
||||
}
|
||||
e.p.Neg(a.p)
|
||||
return e
|
||||
}
|
||||
|
||||
// Set sets e to a and then returns e.
|
||||
func (e *G2) Set(a *G2) *G2 {
|
||||
if e.p == nil {
|
||||
e.p = &twistPoint{}
|
||||
}
|
||||
e.p.Set(a.p)
|
||||
return e
|
||||
}
|
||||
|
||||
// Marshal converts e into a byte slice.
|
||||
func (e *G2) Marshal() []byte {
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
|
||||
if e.p == nil {
|
||||
e.p = &twistPoint{}
|
||||
}
|
||||
|
||||
e.p.MakeAffine()
|
||||
ret := make([]byte, numBytes*4)
|
||||
if e.p.IsInfinity() {
|
||||
return ret
|
||||
}
|
||||
temp := &gfP{}
|
||||
|
||||
montDecode(temp, &e.p.x.x)
|
||||
temp.Marshal(ret)
|
||||
montDecode(temp, &e.p.x.y)
|
||||
temp.Marshal(ret[numBytes:])
|
||||
montDecode(temp, &e.p.y.x)
|
||||
temp.Marshal(ret[2*numBytes:])
|
||||
montDecode(temp, &e.p.y.y)
|
||||
temp.Marshal(ret[3*numBytes:])
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Unmarshal sets e to the result of converting the output of Marshal back into
|
||||
// a group element and then returns e.
|
||||
func (e *G2) Unmarshal(m []byte) ([]byte, error) {
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
if len(m) < 4*numBytes {
|
||||
return nil, errors.New("bn256: not enough data")
|
||||
}
|
||||
// Unmarshal the points and check their caps
|
||||
if e.p == nil {
|
||||
e.p = &twistPoint{}
|
||||
}
|
||||
var err error
|
||||
if err = e.p.x.x.Unmarshal(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.x.y.Unmarshal(m[numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.y.x.Unmarshal(m[2*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.y.y.Unmarshal(m[3*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Encode into Montgomery form and ensure it's on the curve
|
||||
montEncode(&e.p.x.x, &e.p.x.x)
|
||||
montEncode(&e.p.x.y, &e.p.x.y)
|
||||
montEncode(&e.p.y.x, &e.p.y.x)
|
||||
montEncode(&e.p.y.y, &e.p.y.y)
|
||||
|
||||
if e.p.x.IsZero() && e.p.y.IsZero() {
|
||||
// This is the point at infinity.
|
||||
e.p.y.SetOne()
|
||||
e.p.z.SetZero()
|
||||
e.p.t.SetZero()
|
||||
} else {
|
||||
e.p.z.SetOne()
|
||||
e.p.t.SetOne()
|
||||
|
||||
if !e.p.IsOnCurve() {
|
||||
return nil, errors.New("bn256: malformed point")
|
||||
}
|
||||
}
|
||||
return m[4*numBytes:], nil
|
||||
}
|
||||
|
||||
// GT is an abstract cyclic group. The zero value is suitable for use as the
|
||||
// output of an operation, but cannot be used as an input.
|
||||
type GT struct {
|
||||
p *gfP12
|
||||
}
|
||||
|
||||
// Pair calculates an Optimal Ate pairing.
|
||||
func Pair(g1 *G1, g2 *G2) *GT {
|
||||
return >{optimalAte(g2.p, g1.p)}
|
||||
}
|
||||
|
||||
// PairingCheck calculates the Optimal Ate pairing for a set of points.
|
||||
func PairingCheck(a []*G1, b []*G2) bool {
|
||||
acc := new(gfP12)
|
||||
acc.SetOne()
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
if a[i].p.IsInfinity() || b[i].p.IsInfinity() {
|
||||
continue
|
||||
}
|
||||
acc.Mul(acc, miller(b[i].p, a[i].p))
|
||||
}
|
||||
return finalExponentiation(acc).IsOne()
|
||||
}
|
||||
|
||||
// Miller applies Miller's algorithm, which is a bilinear function from the
|
||||
// source groups to F_p^12. Miller(g1, g2).Finalize() is equivalent to Pair(g1,
|
||||
// g2).
|
||||
func Miller(g1 *G1, g2 *G2) *GT {
|
||||
return >{miller(g2.p, g1.p)}
|
||||
}
|
||||
|
||||
func (g *GT) String() string {
|
||||
return "bn256.GT" + g.p.String()
|
||||
}
|
||||
|
||||
// ScalarMult sets e to a*k and then returns e.
|
||||
func (e *GT) ScalarMult(a *GT, k *big.Int) *GT {
|
||||
if e.p == nil {
|
||||
e.p = &gfP12{}
|
||||
}
|
||||
e.p.Exp(a.p, k)
|
||||
return e
|
||||
}
|
||||
|
||||
// Add sets e to a+b and then returns e.
|
||||
func (e *GT) Add(a, b *GT) *GT {
|
||||
if e.p == nil {
|
||||
e.p = &gfP12{}
|
||||
}
|
||||
e.p.Mul(a.p, b.p)
|
||||
return e
|
||||
}
|
||||
|
||||
// Neg sets e to -a and then returns e.
|
||||
func (e *GT) Neg(a *GT) *GT {
|
||||
if e.p == nil {
|
||||
e.p = &gfP12{}
|
||||
}
|
||||
e.p.Conjugate(a.p)
|
||||
return e
|
||||
}
|
||||
|
||||
// Set sets e to a and then returns e.
|
||||
func (e *GT) Set(a *GT) *GT {
|
||||
if e.p == nil {
|
||||
e.p = &gfP12{}
|
||||
}
|
||||
e.p.Set(a.p)
|
||||
return e
|
||||
}
|
||||
|
||||
// Finalize is a linear function from F_p^12 to GT.
|
||||
func (e *GT) Finalize() *GT {
|
||||
ret := finalExponentiation(e.p)
|
||||
e.p.Set(ret)
|
||||
return e
|
||||
}
|
||||
|
||||
// Marshal converts e into a byte slice.
|
||||
func (e *GT) Marshal() []byte {
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
|
||||
ret := make([]byte, numBytes*12)
|
||||
temp := &gfP{}
|
||||
|
||||
montDecode(temp, &e.p.x.x.x)
|
||||
temp.Marshal(ret)
|
||||
montDecode(temp, &e.p.x.x.y)
|
||||
temp.Marshal(ret[numBytes:])
|
||||
montDecode(temp, &e.p.x.y.x)
|
||||
temp.Marshal(ret[2*numBytes:])
|
||||
montDecode(temp, &e.p.x.y.y)
|
||||
temp.Marshal(ret[3*numBytes:])
|
||||
montDecode(temp, &e.p.x.z.x)
|
||||
temp.Marshal(ret[4*numBytes:])
|
||||
montDecode(temp, &e.p.x.z.y)
|
||||
temp.Marshal(ret[5*numBytes:])
|
||||
montDecode(temp, &e.p.y.x.x)
|
||||
temp.Marshal(ret[6*numBytes:])
|
||||
montDecode(temp, &e.p.y.x.y)
|
||||
temp.Marshal(ret[7*numBytes:])
|
||||
montDecode(temp, &e.p.y.y.x)
|
||||
temp.Marshal(ret[8*numBytes:])
|
||||
montDecode(temp, &e.p.y.y.y)
|
||||
temp.Marshal(ret[9*numBytes:])
|
||||
montDecode(temp, &e.p.y.z.x)
|
||||
temp.Marshal(ret[10*numBytes:])
|
||||
montDecode(temp, &e.p.y.z.y)
|
||||
temp.Marshal(ret[11*numBytes:])
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Unmarshal sets e to the result of converting the output of Marshal back into
|
||||
// a group element and then returns e.
|
||||
func (e *GT) Unmarshal(m []byte) ([]byte, error) {
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
|
||||
if len(m) < 12*numBytes {
|
||||
return nil, errors.New("bn256: not enough data")
|
||||
}
|
||||
|
||||
if e.p == nil {
|
||||
e.p = &gfP12{}
|
||||
}
|
||||
|
||||
var err error
|
||||
if err = e.p.x.x.x.Unmarshal(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.x.x.y.Unmarshal(m[numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.x.y.x.Unmarshal(m[2*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.x.y.y.Unmarshal(m[3*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.x.z.x.Unmarshal(m[4*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.x.z.y.Unmarshal(m[5*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.y.x.x.Unmarshal(m[6*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.y.x.y.Unmarshal(m[7*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.y.y.x.Unmarshal(m[8*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.y.y.y.Unmarshal(m[9*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.y.z.x.Unmarshal(m[10*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = e.p.y.z.y.Unmarshal(m[11*numBytes:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
montEncode(&e.p.x.x.x, &e.p.x.x.x)
|
||||
montEncode(&e.p.x.x.y, &e.p.x.x.y)
|
||||
montEncode(&e.p.x.y.x, &e.p.x.y.x)
|
||||
montEncode(&e.p.x.y.y, &e.p.x.y.y)
|
||||
montEncode(&e.p.x.z.x, &e.p.x.z.x)
|
||||
montEncode(&e.p.x.z.y, &e.p.x.z.y)
|
||||
montEncode(&e.p.y.x.x, &e.p.y.x.x)
|
||||
montEncode(&e.p.y.x.y, &e.p.y.x.y)
|
||||
montEncode(&e.p.y.y.x, &e.p.y.y.x)
|
||||
montEncode(&e.p.y.y.y, &e.p.y.y.y)
|
||||
montEncode(&e.p.y.z.x, &e.p.y.z.x)
|
||||
montEncode(&e.p.y.z.y, &e.p.y.z.y)
|
||||
|
||||
return m[12*numBytes:], nil
|
||||
}
|
||||
118
crypto/bn256/cloudflare/bn256_test.go
Normal file
118
crypto/bn256/cloudflare/bn256_test.go
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestG1Marshal(t *testing.T) {
|
||||
_, Ga, err := RandomG1(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ma := Ga.Marshal()
|
||||
|
||||
Gb := new(G1)
|
||||
_, err = Gb.Unmarshal(ma)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mb := Gb.Marshal()
|
||||
|
||||
if !bytes.Equal(ma, mb) {
|
||||
t.Fatal("bytes are different")
|
||||
}
|
||||
}
|
||||
|
||||
func TestG2Marshal(t *testing.T) {
|
||||
_, Ga, err := RandomG2(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ma := Ga.Marshal()
|
||||
|
||||
Gb := new(G2)
|
||||
_, err = Gb.Unmarshal(ma)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mb := Gb.Marshal()
|
||||
|
||||
if !bytes.Equal(ma, mb) {
|
||||
t.Fatal("bytes are different")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBilinearity(t *testing.T) {
|
||||
for i := 0; i < 2; i++ {
|
||||
a, p1, _ := RandomG1(rand.Reader)
|
||||
b, p2, _ := RandomG2(rand.Reader)
|
||||
e1 := Pair(p1, p2)
|
||||
|
||||
e2 := Pair(&G1{curveGen}, &G2{twistGen})
|
||||
e2.ScalarMult(e2, a)
|
||||
e2.ScalarMult(e2, b)
|
||||
|
||||
if *e1.p != *e2.p {
|
||||
t.Fatalf("bad pairing result: %s", e1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTripartiteDiffieHellman(t *testing.T) {
|
||||
a, _ := rand.Int(rand.Reader, Order)
|
||||
b, _ := rand.Int(rand.Reader, Order)
|
||||
c, _ := rand.Int(rand.Reader, Order)
|
||||
|
||||
pa, pb, pc := new(G1), new(G1), new(G1)
|
||||
qa, qb, qc := new(G2), new(G2), new(G2)
|
||||
|
||||
pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal())
|
||||
qa.Unmarshal(new(G2).ScalarBaseMult(a).Marshal())
|
||||
pb.Unmarshal(new(G1).ScalarBaseMult(b).Marshal())
|
||||
qb.Unmarshal(new(G2).ScalarBaseMult(b).Marshal())
|
||||
pc.Unmarshal(new(G1).ScalarBaseMult(c).Marshal())
|
||||
qc.Unmarshal(new(G2).ScalarBaseMult(c).Marshal())
|
||||
|
||||
k1 := Pair(pb, qc)
|
||||
k1.ScalarMult(k1, a)
|
||||
k1Bytes := k1.Marshal()
|
||||
|
||||
k2 := Pair(pc, qa)
|
||||
k2.ScalarMult(k2, b)
|
||||
k2Bytes := k2.Marshal()
|
||||
|
||||
k3 := Pair(pa, qb)
|
||||
k3.ScalarMult(k3, c)
|
||||
k3Bytes := k3.Marshal()
|
||||
|
||||
if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) {
|
||||
t.Errorf("keys didn't agree")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkG1(b *testing.B) {
|
||||
x, _ := rand.Int(rand.Reader, Order)
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
new(G1).ScalarBaseMult(x)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkG2(b *testing.B) {
|
||||
x, _ := rand.Int(rand.Reader, Order)
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
new(G2).ScalarBaseMult(x)
|
||||
}
|
||||
}
|
||||
func BenchmarkPairing(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Pair(&G1{curveGen}, &G2{twistGen})
|
||||
}
|
||||
}
|
||||
59
crypto/bn256/cloudflare/constants.go
Normal file
59
crypto/bn256/cloudflare/constants.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func bigFromBase10(s string) *big.Int {
|
||||
n, _ := new(big.Int).SetString(s, 10)
|
||||
return n
|
||||
}
|
||||
|
||||
// u is the BN parameter that determines the prime: 1868033³.
|
||||
var u = bigFromBase10("4965661367192848881")
|
||||
|
||||
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
|
||||
var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617")
|
||||
|
||||
// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
|
||||
var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583")
|
||||
|
||||
// p2 is p, represented as little-endian 64-bit words.
|
||||
var p2 = [4]uint64{0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029}
|
||||
|
||||
// np is the negative inverse of p, mod 2^256.
|
||||
var np = [4]uint64{0x87d20782e4866389, 0x9ede7d651eca6ac9, 0xd8afcbd01833da80, 0xf57a22b791888c6b}
|
||||
|
||||
// rN1 is R^-1 where R = 2^256 mod p.
|
||||
var rN1 = &gfP{0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9, 0x2e67157159e5c639}
|
||||
|
||||
// r2 is R^2 where R = 2^256 mod p.
|
||||
var r2 = &gfP{0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f}
|
||||
|
||||
// r3 is R^3 where R = 2^256 mod p.
|
||||
var r3 = &gfP{0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544}
|
||||
|
||||
// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9.
|
||||
var xiToPMinus1Over6 = &gfP2{gfP{0xa222ae234c492d72, 0xd00f02a4565de15b, 0xdc2ff3a253dfc926, 0x10a75716b3899551}, gfP{0xaf9ba69633144907, 0xca6b1d7387afb78a, 0x11bded5ef08a2087, 0x02f34d751a1f3a7c}}
|
||||
|
||||
// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9.
|
||||
var xiToPMinus1Over3 = &gfP2{gfP{0x6e849f1ea0aa4757, 0xaa1c7b6d89f89141, 0xb6e713cdfae0ca3a, 0x26694fbb4e82ebc3}, gfP{0xb5773b104563ab30, 0x347f91c8a9aa6454, 0x7a007127242e0991, 0x1956bcd8118214ec}}
|
||||
|
||||
// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+9.
|
||||
var xiToPMinus1Over2 = &gfP2{gfP{0xa1d77ce45ffe77c7, 0x07affd117826d1db, 0x6d16bd27bb7edc6b, 0x2c87200285defecc}, gfP{0xe4bbdd0c2936b629, 0xbb30f162e133bacb, 0x31a9d1b6f9645366, 0x253570bea500f8dd}}
|
||||
|
||||
// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9.
|
||||
var xiToPSquaredMinus1Over3 = &gfP{0x3350c88e13e80b9c, 0x7dce557cdb5e56b9, 0x6001b4b8b615564a, 0x2682e617020217e0}
|
||||
|
||||
// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p).
|
||||
var xiTo2PSquaredMinus2Over3 = &gfP{0x71930c11d782e155, 0xa6bb947cffbe3323, 0xaa303344d4741444, 0x2c3b3f0d26594943}
|
||||
|
||||
// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p).
|
||||
var xiToPSquaredMinus1Over6 = &gfP{0xca8d800500fa1bf2, 0xf0c5d61468b39769, 0x0e201271ad0d4418, 0x04290f65bad856e6}
|
||||
|
||||
// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9.
|
||||
var xiTo2PMinus2Over3 = &gfP2{gfP{0x5dddfd154bd8c949, 0x62cb29a5a4445b60, 0x37bc870a0c7dd2b9, 0x24830a9d3171f0fd}, gfP{0x7361d77f843abe92, 0xa5bb2bd3273411fb, 0x9c941f314b3e2399, 0x15df9cddbb9fd3ec}}
|
||||
229
crypto/bn256/cloudflare/curve.go
Normal file
229
crypto/bn256/cloudflare/curve.go
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
package bn256
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// curvePoint implements the elliptic curve y²=x³+3. Points are kept in Jacobian
|
||||
// form and t=z² when valid. G₁ is the set of points of this curve on GF(p).
|
||||
type curvePoint struct {
|
||||
x, y, z, t gfP
|
||||
}
|
||||
|
||||
var curveB = newGFp(3)
|
||||
|
||||
// curveGen is the generator of G₁.
|
||||
var curveGen = &curvePoint{
|
||||
x: *newGFp(1),
|
||||
y: *newGFp(2),
|
||||
z: *newGFp(1),
|
||||
t: *newGFp(1),
|
||||
}
|
||||
|
||||
func (c *curvePoint) String() string {
|
||||
c.MakeAffine()
|
||||
x, y := &gfP{}, &gfP{}
|
||||
montDecode(x, &c.x)
|
||||
montDecode(y, &c.y)
|
||||
return "(" + x.String() + ", " + y.String() + ")"
|
||||
}
|
||||
|
||||
func (c *curvePoint) Set(a *curvePoint) {
|
||||
c.x.Set(&a.x)
|
||||
c.y.Set(&a.y)
|
||||
c.z.Set(&a.z)
|
||||
c.t.Set(&a.t)
|
||||
}
|
||||
|
||||
// IsOnCurve returns true iff c is on the curve.
|
||||
func (c *curvePoint) IsOnCurve() bool {
|
||||
c.MakeAffine()
|
||||
if c.IsInfinity() {
|
||||
return true
|
||||
}
|
||||
|
||||
y2, x3 := &gfP{}, &gfP{}
|
||||
gfpMul(y2, &c.y, &c.y)
|
||||
gfpMul(x3, &c.x, &c.x)
|
||||
gfpMul(x3, x3, &c.x)
|
||||
gfpAdd(x3, x3, curveB)
|
||||
|
||||
return *y2 == *x3
|
||||
}
|
||||
|
||||
func (c *curvePoint) SetInfinity() {
|
||||
c.x = gfP{0}
|
||||
c.y = *newGFp(1)
|
||||
c.z = gfP{0}
|
||||
c.t = gfP{0}
|
||||
}
|
||||
|
||||
func (c *curvePoint) IsInfinity() bool {
|
||||
return c.z == gfP{0}
|
||||
}
|
||||
|
||||
func (c *curvePoint) Add(a, b *curvePoint) {
|
||||
if a.IsInfinity() {
|
||||
c.Set(b)
|
||||
return
|
||||
}
|
||||
if b.IsInfinity() {
|
||||
c.Set(a)
|
||||
return
|
||||
}
|
||||
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
|
||||
|
||||
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
|
||||
// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
|
||||
// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
|
||||
z12, z22 := &gfP{}, &gfP{}
|
||||
gfpMul(z12, &a.z, &a.z)
|
||||
gfpMul(z22, &b.z, &b.z)
|
||||
|
||||
u1, u2 := &gfP{}, &gfP{}
|
||||
gfpMul(u1, &a.x, z22)
|
||||
gfpMul(u2, &b.x, z12)
|
||||
|
||||
t, s1 := &gfP{}, &gfP{}
|
||||
gfpMul(t, &b.z, z22)
|
||||
gfpMul(s1, &a.y, t)
|
||||
|
||||
s2 := &gfP{}
|
||||
gfpMul(t, &a.z, z12)
|
||||
gfpMul(s2, &b.y, t)
|
||||
|
||||
// Compute x = (2h)²(s²-u1-u2)
|
||||
// where s = (s2-s1)/(u2-u1) is the slope of the line through
|
||||
// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
|
||||
// This is also:
|
||||
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
|
||||
// = r² - j - 2v
|
||||
// with the notations below.
|
||||
h := &gfP{}
|
||||
gfpSub(h, u2, u1)
|
||||
xEqual := *h == gfP{0}
|
||||
|
||||
gfpAdd(t, h, h)
|
||||
// i = 4h²
|
||||
i := &gfP{}
|
||||
gfpMul(i, t, t)
|
||||
// j = 4h³
|
||||
j := &gfP{}
|
||||
gfpMul(j, h, i)
|
||||
|
||||
gfpSub(t, s2, s1)
|
||||
yEqual := *t == gfP{0}
|
||||
if xEqual && yEqual {
|
||||
c.Double(a)
|
||||
return
|
||||
}
|
||||
r := &gfP{}
|
||||
gfpAdd(r, t, t)
|
||||
|
||||
v := &gfP{}
|
||||
gfpMul(v, u1, i)
|
||||
|
||||
// t4 = 4(s2-s1)²
|
||||
t4, t6 := &gfP{}, &gfP{}
|
||||
gfpMul(t4, r, r)
|
||||
gfpAdd(t, v, v)
|
||||
gfpSub(t6, t4, j)
|
||||
|
||||
gfpSub(&c.x, t6, t)
|
||||
|
||||
// Set y = -(2h)³(s1 + s*(x/4h²-u1))
|
||||
// This is also
|
||||
// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
|
||||
gfpSub(t, v, &c.x) // t7
|
||||
gfpMul(t4, s1, j) // t8
|
||||
gfpAdd(t6, t4, t4) // t9
|
||||
gfpMul(t4, r, t) // t10
|
||||
gfpSub(&c.y, t4, t6)
|
||||
|
||||
// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
|
||||
gfpAdd(t, &a.z, &b.z) // t11
|
||||
gfpMul(t4, t, t) // t12
|
||||
gfpSub(t, t4, z12) // t13
|
||||
gfpSub(t4, t, z22) // t14
|
||||
gfpMul(&c.z, t4, h)
|
||||
}
|
||||
|
||||
func (c *curvePoint) Double(a *curvePoint) {
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
|
||||
A, B, C := &gfP{}, &gfP{}, &gfP{}
|
||||
gfpMul(A, &a.x, &a.x)
|
||||
gfpMul(B, &a.y, &a.y)
|
||||
gfpMul(C, B, B)
|
||||
|
||||
t, t2 := &gfP{}, &gfP{}
|
||||
gfpAdd(t, &a.x, B)
|
||||
gfpMul(t2, t, t)
|
||||
gfpSub(t, t2, A)
|
||||
gfpSub(t2, t, C)
|
||||
|
||||
d, e, f := &gfP{}, &gfP{}, &gfP{}
|
||||
gfpAdd(d, t2, t2)
|
||||
gfpAdd(t, A, A)
|
||||
gfpAdd(e, t, A)
|
||||
gfpMul(f, e, e)
|
||||
|
||||
gfpAdd(t, d, d)
|
||||
gfpSub(&c.x, f, t)
|
||||
|
||||
gfpAdd(t, C, C)
|
||||
gfpAdd(t2, t, t)
|
||||
gfpAdd(t, t2, t2)
|
||||
gfpSub(&c.y, d, &c.x)
|
||||
gfpMul(t2, e, &c.y)
|
||||
gfpSub(&c.y, t2, t)
|
||||
|
||||
gfpMul(t, &a.y, &a.z)
|
||||
gfpAdd(&c.z, t, t)
|
||||
}
|
||||
|
||||
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
|
||||
sum, t := &curvePoint{}, &curvePoint{}
|
||||
sum.SetInfinity()
|
||||
|
||||
for i := scalar.BitLen(); i >= 0; i-- {
|
||||
t.Double(sum)
|
||||
if scalar.Bit(i) != 0 {
|
||||
sum.Add(t, a)
|
||||
} else {
|
||||
sum.Set(t)
|
||||
}
|
||||
}
|
||||
c.Set(sum)
|
||||
}
|
||||
|
||||
func (c *curvePoint) MakeAffine() {
|
||||
if c.z == *newGFp(1) {
|
||||
return
|
||||
} else if c.z == *newGFp(0) {
|
||||
c.x = gfP{0}
|
||||
c.y = *newGFp(1)
|
||||
c.t = gfP{0}
|
||||
return
|
||||
}
|
||||
|
||||
zInv := &gfP{}
|
||||
zInv.Invert(&c.z)
|
||||
|
||||
t, zInv2 := &gfP{}, &gfP{}
|
||||
gfpMul(t, &c.y, zInv)
|
||||
gfpMul(zInv2, zInv, zInv)
|
||||
|
||||
gfpMul(&c.x, &c.x, zInv2)
|
||||
gfpMul(&c.y, t, zInv2)
|
||||
|
||||
c.z = *newGFp(1)
|
||||
c.t = *newGFp(1)
|
||||
}
|
||||
|
||||
func (c *curvePoint) Neg(a *curvePoint) {
|
||||
c.x.Set(&a.x)
|
||||
gfpNeg(&c.y, &a.y)
|
||||
c.z.Set(&a.z)
|
||||
c.t = gfP{0}
|
||||
}
|
||||
45
crypto/bn256/cloudflare/example_test.go
Normal file
45
crypto/bn256/cloudflare/example_test.go
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
func ExamplePair() {
|
||||
// This implements the tripartite Diffie-Hellman algorithm from "A One
|
||||
// Round Protocol for Tripartite Diffie-Hellman", A. Joux.
|
||||
// http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf
|
||||
|
||||
// Each of three parties, a, b and c, generate a private value.
|
||||
a, _ := rand.Int(rand.Reader, Order)
|
||||
b, _ := rand.Int(rand.Reader, Order)
|
||||
c, _ := rand.Int(rand.Reader, Order)
|
||||
|
||||
// Then each party calculates g₁ and g₂ times their private value.
|
||||
pa := new(G1).ScalarBaseMult(a)
|
||||
qa := new(G2).ScalarBaseMult(a)
|
||||
|
||||
pb := new(G1).ScalarBaseMult(b)
|
||||
qb := new(G2).ScalarBaseMult(b)
|
||||
|
||||
pc := new(G1).ScalarBaseMult(c)
|
||||
qc := new(G2).ScalarBaseMult(c)
|
||||
|
||||
// Now each party exchanges its public values with the other two and
|
||||
// all parties can calculate the shared key.
|
||||
k1 := Pair(pb, qc)
|
||||
k1.ScalarMult(k1, a)
|
||||
|
||||
k2 := Pair(pc, qa)
|
||||
k2.ScalarMult(k2, b)
|
||||
|
||||
k3 := Pair(pa, qb)
|
||||
k3.ScalarMult(k3, c)
|
||||
|
||||
// k1, k2 and k3 will all be equal.
|
||||
}
|
||||
81
crypto/bn256/cloudflare/gfp.go
Normal file
81
crypto/bn256/cloudflare/gfp.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package bn256
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type gfP [4]uint64
|
||||
|
||||
func newGFp(x int64) (out *gfP) {
|
||||
if x >= 0 {
|
||||
out = &gfP{uint64(x)}
|
||||
} else {
|
||||
out = &gfP{uint64(-x)}
|
||||
gfpNeg(out, out)
|
||||
}
|
||||
|
||||
montEncode(out, out)
|
||||
return out
|
||||
}
|
||||
|
||||
func (e *gfP) String() string {
|
||||
return fmt.Sprintf("%16.16x%16.16x%16.16x%16.16x", e[3], e[2], e[1], e[0])
|
||||
}
|
||||
|
||||
func (e *gfP) Set(f *gfP) {
|
||||
e[0] = f[0]
|
||||
e[1] = f[1]
|
||||
e[2] = f[2]
|
||||
e[3] = f[3]
|
||||
}
|
||||
|
||||
func (e *gfP) Invert(f *gfP) {
|
||||
bits := [4]uint64{0x3c208c16d87cfd45, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029}
|
||||
|
||||
sum, power := &gfP{}, &gfP{}
|
||||
sum.Set(rN1)
|
||||
power.Set(f)
|
||||
|
||||
for word := 0; word < 4; word++ {
|
||||
for bit := uint(0); bit < 64; bit++ {
|
||||
if (bits[word]>>bit)&1 == 1 {
|
||||
gfpMul(sum, sum, power)
|
||||
}
|
||||
gfpMul(power, power, power)
|
||||
}
|
||||
}
|
||||
|
||||
gfpMul(sum, sum, r3)
|
||||
e.Set(sum)
|
||||
}
|
||||
|
||||
func (e *gfP) Marshal(out []byte) {
|
||||
for w := uint(0); w < 4; w++ {
|
||||
for b := uint(0); b < 8; b++ {
|
||||
out[8*w+b] = byte(e[3-w] >> (56 - 8*b))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e *gfP) Unmarshal(in []byte) error {
|
||||
// Unmarshal the bytes into little endian form
|
||||
for w := uint(0); w < 4; w++ {
|
||||
for b := uint(0); b < 8; b++ {
|
||||
e[3-w] += uint64(in[8*w+b]) << (56 - 8*b)
|
||||
}
|
||||
}
|
||||
// Ensure the point respects the curve modulus
|
||||
for i := 3; i >= 0; i-- {
|
||||
if e[i] < p2[i] {
|
||||
return nil
|
||||
}
|
||||
if e[i] > p2[i] {
|
||||
return errors.New("bn256: coordinate exceeds modulus")
|
||||
}
|
||||
}
|
||||
return errors.New("bn256: coordinate equals modulus")
|
||||
}
|
||||
|
||||
func montEncode(c, a *gfP) { gfpMul(c, a, r2) }
|
||||
func montDecode(c, a *gfP) { gfpMul(c, a, &gfP{1}) }
|
||||
32
crypto/bn256/cloudflare/gfp.h
Normal file
32
crypto/bn256/cloudflare/gfp.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#define storeBlock(a0,a1,a2,a3, r) \
|
||||
MOVQ a0, 0+r \
|
||||
MOVQ a1, 8+r \
|
||||
MOVQ a2, 16+r \
|
||||
MOVQ a3, 24+r
|
||||
|
||||
#define loadBlock(r, a0,a1,a2,a3) \
|
||||
MOVQ 0+r, a0 \
|
||||
MOVQ 8+r, a1 \
|
||||
MOVQ 16+r, a2 \
|
||||
MOVQ 24+r, a3
|
||||
|
||||
#define gfpCarry(a0,a1,a2,a3,a4, b0,b1,b2,b3,b4) \
|
||||
\ // b = a-p
|
||||
MOVQ a0, b0 \
|
||||
MOVQ a1, b1 \
|
||||
MOVQ a2, b2 \
|
||||
MOVQ a3, b3 \
|
||||
MOVQ a4, b4 \
|
||||
\
|
||||
SUBQ ·p2+0(SB), b0 \
|
||||
SBBQ ·p2+8(SB), b1 \
|
||||
SBBQ ·p2+16(SB), b2 \
|
||||
SBBQ ·p2+24(SB), b3 \
|
||||
SBBQ $0, b4 \
|
||||
\
|
||||
\ // if b is negative then return a
|
||||
\ // else return b
|
||||
CMOVQCC b0, a0 \
|
||||
CMOVQCC b1, a1 \
|
||||
CMOVQCC b2, a2 \
|
||||
CMOVQCC b3, a3
|
||||
160
crypto/bn256/cloudflare/gfp12.go
Normal file
160
crypto/bn256/cloudflare/gfp12.go
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
package bn256
|
||||
|
||||
// For details of the algorithms used, see "Multiplication and Squaring on
|
||||
// Pairing-Friendly Fields, Devegili et al.
|
||||
// http://eprint.iacr.org/2006/471.pdf.
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// gfP12 implements the field of size p¹² as a quadratic extension of gfP6
|
||||
// where ω²=τ.
|
||||
type gfP12 struct {
|
||||
x, y gfP6 // value is xω + y
|
||||
}
|
||||
|
||||
func (e *gfP12) String() string {
|
||||
return "(" + e.x.String() + "," + e.y.String() + ")"
|
||||
}
|
||||
|
||||
func (e *gfP12) Set(a *gfP12) *gfP12 {
|
||||
e.x.Set(&a.x)
|
||||
e.y.Set(&a.y)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12) SetZero() *gfP12 {
|
||||
e.x.SetZero()
|
||||
e.y.SetZero()
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12) SetOne() *gfP12 {
|
||||
e.x.SetZero()
|
||||
e.y.SetOne()
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12) IsZero() bool {
|
||||
return e.x.IsZero() && e.y.IsZero()
|
||||
}
|
||||
|
||||
func (e *gfP12) IsOne() bool {
|
||||
return e.x.IsZero() && e.y.IsOne()
|
||||
}
|
||||
|
||||
func (e *gfP12) Conjugate(a *gfP12) *gfP12 {
|
||||
e.x.Neg(&a.x)
|
||||
e.y.Set(&a.y)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12) Neg(a *gfP12) *gfP12 {
|
||||
e.x.Neg(&a.x)
|
||||
e.y.Neg(&a.y)
|
||||
return e
|
||||
}
|
||||
|
||||
// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p
|
||||
func (e *gfP12) Frobenius(a *gfP12) *gfP12 {
|
||||
e.x.Frobenius(&a.x)
|
||||
e.y.Frobenius(&a.y)
|
||||
e.x.MulScalar(&e.x, xiToPMinus1Over6)
|
||||
return e
|
||||
}
|
||||
|
||||
// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p²
|
||||
func (e *gfP12) FrobeniusP2(a *gfP12) *gfP12 {
|
||||
e.x.FrobeniusP2(&a.x)
|
||||
e.x.MulGFP(&e.x, xiToPSquaredMinus1Over6)
|
||||
e.y.FrobeniusP2(&a.y)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12) FrobeniusP4(a *gfP12) *gfP12 {
|
||||
e.x.FrobeniusP4(&a.x)
|
||||
e.x.MulGFP(&e.x, xiToPSquaredMinus1Over3)
|
||||
e.y.FrobeniusP4(&a.y)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12) Add(a, b *gfP12) *gfP12 {
|
||||
e.x.Add(&a.x, &b.x)
|
||||
e.y.Add(&a.y, &b.y)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12) Sub(a, b *gfP12) *gfP12 {
|
||||
e.x.Sub(&a.x, &b.x)
|
||||
e.y.Sub(&a.y, &b.y)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12) Mul(a, b *gfP12) *gfP12 {
|
||||
tx := (&gfP6{}).Mul(&a.x, &b.y)
|
||||
t := (&gfP6{}).Mul(&b.x, &a.y)
|
||||
tx.Add(tx, t)
|
||||
|
||||
ty := (&gfP6{}).Mul(&a.y, &b.y)
|
||||
t.Mul(&a.x, &b.x).MulTau(t)
|
||||
|
||||
e.x.Set(tx)
|
||||
e.y.Add(ty, t)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 {
|
||||
e.x.Mul(&e.x, b)
|
||||
e.y.Mul(&e.y, b)
|
||||
return e
|
||||
}
|
||||
|
||||
func (c *gfP12) Exp(a *gfP12, power *big.Int) *gfP12 {
|
||||
sum := (&gfP12{}).SetOne()
|
||||
t := &gfP12{}
|
||||
|
||||
for i := power.BitLen() - 1; i >= 0; i-- {
|
||||
t.Square(sum)
|
||||
if power.Bit(i) != 0 {
|
||||
sum.Mul(t, a)
|
||||
} else {
|
||||
sum.Set(t)
|
||||
}
|
||||
}
|
||||
|
||||
c.Set(sum)
|
||||
return c
|
||||
}
|
||||
|
||||
func (e *gfP12) Square(a *gfP12) *gfP12 {
|
||||
// Complex squaring algorithm
|
||||
v0 := (&gfP6{}).Mul(&a.x, &a.y)
|
||||
|
||||
t := (&gfP6{}).MulTau(&a.x)
|
||||
t.Add(&a.y, t)
|
||||
ty := (&gfP6{}).Add(&a.x, &a.y)
|
||||
ty.Mul(ty, t).Sub(ty, v0)
|
||||
t.MulTau(v0)
|
||||
ty.Sub(ty, t)
|
||||
|
||||
e.x.Add(v0, v0)
|
||||
e.y.Set(ty)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12) Invert(a *gfP12) *gfP12 {
|
||||
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
|
||||
// ftp://136.206.11.249/pub/crypto/pairings.pdf
|
||||
t1, t2 := &gfP6{}, &gfP6{}
|
||||
|
||||
t1.Square(&a.x)
|
||||
t2.Square(&a.y)
|
||||
t1.MulTau(t1).Sub(t2, t1)
|
||||
t2.Invert(t1)
|
||||
|
||||
e.x.Neg(&a.x)
|
||||
e.y.Set(&a.y)
|
||||
e.MulScalar(e, t2)
|
||||
return e
|
||||
}
|
||||
156
crypto/bn256/cloudflare/gfp2.go
Normal file
156
crypto/bn256/cloudflare/gfp2.go
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
package bn256
|
||||
|
||||
// For details of the algorithms used, see "Multiplication and Squaring on
|
||||
// Pairing-Friendly Fields, Devegili et al.
|
||||
// http://eprint.iacr.org/2006/471.pdf.
|
||||
|
||||
// gfP2 implements a field of size p² as a quadratic extension of the base field
|
||||
// where i²=-1.
|
||||
type gfP2 struct {
|
||||
x, y gfP // value is xi+y.
|
||||
}
|
||||
|
||||
func gfP2Decode(in *gfP2) *gfP2 {
|
||||
out := &gfP2{}
|
||||
montDecode(&out.x, &in.x)
|
||||
montDecode(&out.y, &in.y)
|
||||
return out
|
||||
}
|
||||
|
||||
func (e *gfP2) String() string {
|
||||
return "(" + e.x.String() + ", " + e.y.String() + ")"
|
||||
}
|
||||
|
||||
func (e *gfP2) Set(a *gfP2) *gfP2 {
|
||||
e.x.Set(&a.x)
|
||||
e.y.Set(&a.y)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) SetZero() *gfP2 {
|
||||
e.x = gfP{0}
|
||||
e.y = gfP{0}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) SetOne() *gfP2 {
|
||||
e.x = gfP{0}
|
||||
e.y = *newGFp(1)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) IsZero() bool {
|
||||
zero := gfP{0}
|
||||
return e.x == zero && e.y == zero
|
||||
}
|
||||
|
||||
func (e *gfP2) IsOne() bool {
|
||||
zero, one := gfP{0}, *newGFp(1)
|
||||
return e.x == zero && e.y == one
|
||||
}
|
||||
|
||||
func (e *gfP2) Conjugate(a *gfP2) *gfP2 {
|
||||
e.y.Set(&a.y)
|
||||
gfpNeg(&e.x, &a.x)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) Neg(a *gfP2) *gfP2 {
|
||||
gfpNeg(&e.x, &a.x)
|
||||
gfpNeg(&e.y, &a.y)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) Add(a, b *gfP2) *gfP2 {
|
||||
gfpAdd(&e.x, &a.x, &b.x)
|
||||
gfpAdd(&e.y, &a.y, &b.y)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) Sub(a, b *gfP2) *gfP2 {
|
||||
gfpSub(&e.x, &a.x, &b.x)
|
||||
gfpSub(&e.y, &a.y, &b.y)
|
||||
return e
|
||||
}
|
||||
|
||||
// See "Multiplication and Squaring in Pairing-Friendly Fields",
|
||||
// http://eprint.iacr.org/2006/471.pdf
|
||||
func (e *gfP2) Mul(a, b *gfP2) *gfP2 {
|
||||
tx, t := &gfP{}, &gfP{}
|
||||
gfpMul(tx, &a.x, &b.y)
|
||||
gfpMul(t, &b.x, &a.y)
|
||||
gfpAdd(tx, tx, t)
|
||||
|
||||
ty := &gfP{}
|
||||
gfpMul(ty, &a.y, &b.y)
|
||||
gfpMul(t, &a.x, &b.x)
|
||||
gfpSub(ty, ty, t)
|
||||
|
||||
e.x.Set(tx)
|
||||
e.y.Set(ty)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 {
|
||||
gfpMul(&e.x, &a.x, b)
|
||||
gfpMul(&e.y, &a.y, b)
|
||||
return e
|
||||
}
|
||||
|
||||
// MulXi sets e=ξa where ξ=i+9 and then returns e.
|
||||
func (e *gfP2) MulXi(a *gfP2) *gfP2 {
|
||||
// (xi+y)(i+9) = (9x+y)i+(9y-x)
|
||||
tx := &gfP{}
|
||||
gfpAdd(tx, &a.x, &a.x)
|
||||
gfpAdd(tx, tx, tx)
|
||||
gfpAdd(tx, tx, tx)
|
||||
gfpAdd(tx, tx, &a.x)
|
||||
|
||||
gfpAdd(tx, tx, &a.y)
|
||||
|
||||
ty := &gfP{}
|
||||
gfpAdd(ty, &a.y, &a.y)
|
||||
gfpAdd(ty, ty, ty)
|
||||
gfpAdd(ty, ty, ty)
|
||||
gfpAdd(ty, ty, &a.y)
|
||||
|
||||
gfpSub(ty, ty, &a.x)
|
||||
|
||||
e.x.Set(tx)
|
||||
e.y.Set(ty)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) Square(a *gfP2) *gfP2 {
|
||||
// Complex squaring algorithm:
|
||||
// (xi+y)² = (x+y)(y-x) + 2*i*x*y
|
||||
tx, ty := &gfP{}, &gfP{}
|
||||
gfpSub(tx, &a.y, &a.x)
|
||||
gfpAdd(ty, &a.x, &a.y)
|
||||
gfpMul(ty, tx, ty)
|
||||
|
||||
gfpMul(tx, &a.x, &a.y)
|
||||
gfpAdd(tx, tx, tx)
|
||||
|
||||
e.x.Set(tx)
|
||||
e.y.Set(ty)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) Invert(a *gfP2) *gfP2 {
|
||||
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
|
||||
// ftp://136.206.11.249/pub/crypto/pairings.pdf
|
||||
t1, t2 := &gfP{}, &gfP{}
|
||||
gfpMul(t1, &a.x, &a.x)
|
||||
gfpMul(t2, &a.y, &a.y)
|
||||
gfpAdd(t1, t1, t2)
|
||||
|
||||
inv := &gfP{}
|
||||
inv.Invert(t1)
|
||||
|
||||
gfpNeg(t1, &a.x)
|
||||
|
||||
gfpMul(&e.x, t1, inv)
|
||||
gfpMul(&e.y, &a.y, inv)
|
||||
return e
|
||||
}
|
||||
213
crypto/bn256/cloudflare/gfp6.go
Normal file
213
crypto/bn256/cloudflare/gfp6.go
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
package bn256
|
||||
|
||||
// For details of the algorithms used, see "Multiplication and Squaring on
|
||||
// Pairing-Friendly Fields, Devegili et al.
|
||||
// http://eprint.iacr.org/2006/471.pdf.
|
||||
|
||||
// gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ
|
||||
// and ξ=i+3.
|
||||
type gfP6 struct {
|
||||
x, y, z gfP2 // value is xτ² + yτ + z
|
||||
}
|
||||
|
||||
func (e *gfP6) String() string {
|
||||
return "(" + e.x.String() + ", " + e.y.String() + ", " + e.z.String() + ")"
|
||||
}
|
||||
|
||||
func (e *gfP6) Set(a *gfP6) *gfP6 {
|
||||
e.x.Set(&a.x)
|
||||
e.y.Set(&a.y)
|
||||
e.z.Set(&a.z)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) SetZero() *gfP6 {
|
||||
e.x.SetZero()
|
||||
e.y.SetZero()
|
||||
e.z.SetZero()
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) SetOne() *gfP6 {
|
||||
e.x.SetZero()
|
||||
e.y.SetZero()
|
||||
e.z.SetOne()
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) IsZero() bool {
|
||||
return e.x.IsZero() && e.y.IsZero() && e.z.IsZero()
|
||||
}
|
||||
|
||||
func (e *gfP6) IsOne() bool {
|
||||
return e.x.IsZero() && e.y.IsZero() && e.z.IsOne()
|
||||
}
|
||||
|
||||
func (e *gfP6) Neg(a *gfP6) *gfP6 {
|
||||
e.x.Neg(&a.x)
|
||||
e.y.Neg(&a.y)
|
||||
e.z.Neg(&a.z)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) Frobenius(a *gfP6) *gfP6 {
|
||||
e.x.Conjugate(&a.x)
|
||||
e.y.Conjugate(&a.y)
|
||||
e.z.Conjugate(&a.z)
|
||||
|
||||
e.x.Mul(&e.x, xiTo2PMinus2Over3)
|
||||
e.y.Mul(&e.y, xiToPMinus1Over3)
|
||||
return e
|
||||
}
|
||||
|
||||
// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
|
||||
func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 {
|
||||
// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
|
||||
e.x.MulScalar(&a.x, xiTo2PSquaredMinus2Over3)
|
||||
// τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
|
||||
e.y.MulScalar(&a.y, xiToPSquaredMinus1Over3)
|
||||
e.z.Set(&a.z)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) FrobeniusP4(a *gfP6) *gfP6 {
|
||||
e.x.MulScalar(&a.x, xiToPSquaredMinus1Over3)
|
||||
e.y.MulScalar(&a.y, xiTo2PSquaredMinus2Over3)
|
||||
e.z.Set(&a.z)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) Add(a, b *gfP6) *gfP6 {
|
||||
e.x.Add(&a.x, &b.x)
|
||||
e.y.Add(&a.y, &b.y)
|
||||
e.z.Add(&a.z, &b.z)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) Sub(a, b *gfP6) *gfP6 {
|
||||
e.x.Sub(&a.x, &b.x)
|
||||
e.y.Sub(&a.y, &b.y)
|
||||
e.z.Sub(&a.z, &b.z)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) Mul(a, b *gfP6) *gfP6 {
|
||||
// "Multiplication and Squaring on Pairing-Friendly Fields"
|
||||
// Section 4, Karatsuba method.
|
||||
// http://eprint.iacr.org/2006/471.pdf
|
||||
v0 := (&gfP2{}).Mul(&a.z, &b.z)
|
||||
v1 := (&gfP2{}).Mul(&a.y, &b.y)
|
||||
v2 := (&gfP2{}).Mul(&a.x, &b.x)
|
||||
|
||||
t0 := (&gfP2{}).Add(&a.x, &a.y)
|
||||
t1 := (&gfP2{}).Add(&b.x, &b.y)
|
||||
tz := (&gfP2{}).Mul(t0, t1)
|
||||
tz.Sub(tz, v1).Sub(tz, v2).MulXi(tz).Add(tz, v0)
|
||||
|
||||
t0.Add(&a.y, &a.z)
|
||||
t1.Add(&b.y, &b.z)
|
||||
ty := (&gfP2{}).Mul(t0, t1)
|
||||
t0.MulXi(v2)
|
||||
ty.Sub(ty, v0).Sub(ty, v1).Add(ty, t0)
|
||||
|
||||
t0.Add(&a.x, &a.z)
|
||||
t1.Add(&b.x, &b.z)
|
||||
tx := (&gfP2{}).Mul(t0, t1)
|
||||
tx.Sub(tx, v0).Add(tx, v1).Sub(tx, v2)
|
||||
|
||||
e.x.Set(tx)
|
||||
e.y.Set(ty)
|
||||
e.z.Set(tz)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) MulScalar(a *gfP6, b *gfP2) *gfP6 {
|
||||
e.x.Mul(&a.x, b)
|
||||
e.y.Mul(&a.y, b)
|
||||
e.z.Mul(&a.z, b)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) MulGFP(a *gfP6, b *gfP) *gfP6 {
|
||||
e.x.MulScalar(&a.x, b)
|
||||
e.y.MulScalar(&a.y, b)
|
||||
e.z.MulScalar(&a.z, b)
|
||||
return e
|
||||
}
|
||||
|
||||
// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ
|
||||
func (e *gfP6) MulTau(a *gfP6) *gfP6 {
|
||||
tz := (&gfP2{}).MulXi(&a.x)
|
||||
ty := (&gfP2{}).Set(&a.y)
|
||||
|
||||
e.y.Set(&a.z)
|
||||
e.x.Set(ty)
|
||||
e.z.Set(tz)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) Square(a *gfP6) *gfP6 {
|
||||
v0 := (&gfP2{}).Square(&a.z)
|
||||
v1 := (&gfP2{}).Square(&a.y)
|
||||
v2 := (&gfP2{}).Square(&a.x)
|
||||
|
||||
c0 := (&gfP2{}).Add(&a.x, &a.y)
|
||||
c0.Square(c0).Sub(c0, v1).Sub(c0, v2).MulXi(c0).Add(c0, v0)
|
||||
|
||||
c1 := (&gfP2{}).Add(&a.y, &a.z)
|
||||
c1.Square(c1).Sub(c1, v0).Sub(c1, v1)
|
||||
xiV2 := (&gfP2{}).MulXi(v2)
|
||||
c1.Add(c1, xiV2)
|
||||
|
||||
c2 := (&gfP2{}).Add(&a.x, &a.z)
|
||||
c2.Square(c2).Sub(c2, v0).Add(c2, v1).Sub(c2, v2)
|
||||
|
||||
e.x.Set(c2)
|
||||
e.y.Set(c1)
|
||||
e.z.Set(c0)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP6) Invert(a *gfP6) *gfP6 {
|
||||
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
|
||||
// ftp://136.206.11.249/pub/crypto/pairings.pdf
|
||||
|
||||
// Here we can give a short explanation of how it works: let j be a cubic root of
|
||||
// unity in GF(p²) so that 1+j+j²=0.
|
||||
// Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
|
||||
// = (xτ² + yτ + z)(Cτ²+Bτ+A)
|
||||
// = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
|
||||
//
|
||||
// On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
|
||||
// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
|
||||
//
|
||||
// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
|
||||
t1 := (&gfP2{}).Mul(&a.x, &a.y)
|
||||
t1.MulXi(t1)
|
||||
|
||||
A := (&gfP2{}).Square(&a.z)
|
||||
A.Sub(A, t1)
|
||||
|
||||
B := (&gfP2{}).Square(&a.x)
|
||||
B.MulXi(B)
|
||||
t1.Mul(&a.y, &a.z)
|
||||
B.Sub(B, t1)
|
||||
|
||||
C := (&gfP2{}).Square(&a.y)
|
||||
t1.Mul(&a.x, &a.z)
|
||||
C.Sub(C, t1)
|
||||
|
||||
F := (&gfP2{}).Mul(C, &a.y)
|
||||
F.MulXi(F)
|
||||
t1.Mul(A, &a.z)
|
||||
F.Add(F, t1)
|
||||
t1.Mul(B, &a.x).MulXi(t1)
|
||||
F.Add(F, t1)
|
||||
|
||||
F.Invert(F)
|
||||
|
||||
e.x.Mul(C, F)
|
||||
e.y.Mul(B, F)
|
||||
e.z.Mul(A, F)
|
||||
return e
|
||||
}
|
||||
15
crypto/bn256/cloudflare/gfp_amd64.go
Normal file
15
crypto/bn256/cloudflare/gfp_amd64.go
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
package bn256
|
||||
|
||||
// go:noescape
|
||||
func gfpNeg(c, a *gfP)
|
||||
|
||||
//go:noescape
|
||||
func gfpAdd(c, a, b *gfP)
|
||||
|
||||
//go:noescape
|
||||
func gfpSub(c, a, b *gfP)
|
||||
|
||||
//go:noescape
|
||||
func gfpMul(c, a, b *gfP)
|
||||
97
crypto/bn256/cloudflare/gfp_amd64.s
Normal file
97
crypto/bn256/cloudflare/gfp_amd64.s
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
#include "gfp.h"
|
||||
#include "mul.h"
|
||||
#include "mul_bmi2.h"
|
||||
|
||||
TEXT ·gfpNeg(SB),0,$0-16
|
||||
MOVQ ·p2+0(SB), R8
|
||||
MOVQ ·p2+8(SB), R9
|
||||
MOVQ ·p2+16(SB), R10
|
||||
MOVQ ·p2+24(SB), R11
|
||||
|
||||
MOVQ a+8(FP), DI
|
||||
SUBQ 0(DI), R8
|
||||
SBBQ 8(DI), R9
|
||||
SBBQ 16(DI), R10
|
||||
SBBQ 24(DI), R11
|
||||
|
||||
MOVQ $0, AX
|
||||
gfpCarry(R8,R9,R10,R11,AX, R12,R13,R14,R15,BX)
|
||||
|
||||
MOVQ c+0(FP), DI
|
||||
storeBlock(R8,R9,R10,R11, 0(DI))
|
||||
RET
|
||||
|
||||
TEXT ·gfpAdd(SB),0,$0-24
|
||||
MOVQ a+8(FP), DI
|
||||
MOVQ b+16(FP), SI
|
||||
|
||||
loadBlock(0(DI), R8,R9,R10,R11)
|
||||
MOVQ $0, R12
|
||||
|
||||
ADDQ 0(SI), R8
|
||||
ADCQ 8(SI), R9
|
||||
ADCQ 16(SI), R10
|
||||
ADCQ 24(SI), R11
|
||||
ADCQ $0, R12
|
||||
|
||||
gfpCarry(R8,R9,R10,R11,R12, R13,R14,R15,AX,BX)
|
||||
|
||||
MOVQ c+0(FP), DI
|
||||
storeBlock(R8,R9,R10,R11, 0(DI))
|
||||
RET
|
||||
|
||||
TEXT ·gfpSub(SB),0,$0-24
|
||||
MOVQ a+8(FP), DI
|
||||
MOVQ b+16(FP), SI
|
||||
|
||||
loadBlock(0(DI), R8,R9,R10,R11)
|
||||
|
||||
MOVQ ·p2+0(SB), R12
|
||||
MOVQ ·p2+8(SB), R13
|
||||
MOVQ ·p2+16(SB), R14
|
||||
MOVQ ·p2+24(SB), R15
|
||||
MOVQ $0, AX
|
||||
|
||||
SUBQ 0(SI), R8
|
||||
SBBQ 8(SI), R9
|
||||
SBBQ 16(SI), R10
|
||||
SBBQ 24(SI), R11
|
||||
|
||||
CMOVQCC AX, R12
|
||||
CMOVQCC AX, R13
|
||||
CMOVQCC AX, R14
|
||||
CMOVQCC AX, R15
|
||||
|
||||
ADDQ R12, R8
|
||||
ADCQ R13, R9
|
||||
ADCQ R14, R10
|
||||
ADCQ R15, R11
|
||||
|
||||
MOVQ c+0(FP), DI
|
||||
storeBlock(R8,R9,R10,R11, 0(DI))
|
||||
RET
|
||||
|
||||
TEXT ·gfpMul(SB),0,$160-24
|
||||
MOVQ a+8(FP), DI
|
||||
MOVQ b+16(FP), SI
|
||||
|
||||
// Jump to a slightly different implementation if MULX isn't supported.
|
||||
CMPB runtime·support_bmi2(SB), $0
|
||||
JE nobmi2Mul
|
||||
|
||||
mulBMI2(0(DI),8(DI),16(DI),24(DI), 0(SI))
|
||||
storeBlock( R8, R9,R10,R11, 0(SP))
|
||||
storeBlock(R12,R13,R14,R15, 32(SP))
|
||||
gfpReduceBMI2()
|
||||
JMP end
|
||||
|
||||
nobmi2Mul:
|
||||
mul(0(DI),8(DI),16(DI),24(DI), 0(SI), 0(SP))
|
||||
gfpReduce(0(SP))
|
||||
|
||||
end:
|
||||
MOVQ c+0(FP), DI
|
||||
storeBlock(R12,R13,R14,R15, 0(DI))
|
||||
RET
|
||||
19
crypto/bn256/cloudflare/gfp_pure.go
Normal file
19
crypto/bn256/cloudflare/gfp_pure.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// +build !amd64 appengine gccgo
|
||||
|
||||
package bn256
|
||||
|
||||
func gfpNeg(c, a *gfP) {
|
||||
panic("unsupported architecture")
|
||||
}
|
||||
|
||||
func gfpAdd(c, a, b *gfP) {
|
||||
panic("unsupported architecture")
|
||||
}
|
||||
|
||||
func gfpSub(c, a, b *gfP) {
|
||||
panic("unsupported architecture")
|
||||
}
|
||||
|
||||
func gfpMul(c, a, b *gfP) {
|
||||
panic("unsupported architecture")
|
||||
}
|
||||
62
crypto/bn256/cloudflare/gfp_test.go
Normal file
62
crypto/bn256/cloudflare/gfp_test.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Tests that negation works the same way on both assembly-optimized and pure Go
|
||||
// implementation.
|
||||
func TestGFpNeg(t *testing.T) {
|
||||
n := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
|
||||
w := &gfP{0xfedcba9876543211, 0x0123456789abcdef, 0x2152411021524110, 0x0114251201142512}
|
||||
h := &gfP{}
|
||||
|
||||
gfpNeg(h, n)
|
||||
if *h != *w {
|
||||
t.Errorf("negation mismatch: have %#x, want %#x", *h, *w)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that addition works the same way on both assembly-optimized and pure Go
|
||||
// implementation.
|
||||
func TestGFpAdd(t *testing.T) {
|
||||
a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
|
||||
b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef}
|
||||
w := &gfP{0xc3df73e9278302b8, 0x687e956e978e3572, 0x254954275c18417f, 0xad354b6afc67f9b4}
|
||||
h := &gfP{}
|
||||
|
||||
gfpAdd(h, a, b)
|
||||
if *h != *w {
|
||||
t.Errorf("addition mismatch: have %#x, want %#x", *h, *w)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that subtraction works the same way on both assembly-optimized and pure Go
|
||||
// implementation.
|
||||
func TestGFpSub(t *testing.T) {
|
||||
a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
|
||||
b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef}
|
||||
w := &gfP{0x02468acf13579bdf, 0xfdb97530eca86420, 0xdfc1e401dfc1e402, 0x203e1bfe203e1bfd}
|
||||
h := &gfP{}
|
||||
|
||||
gfpSub(h, a, b)
|
||||
if *h != *w {
|
||||
t.Errorf("subtraction mismatch: have %#x, want %#x", *h, *w)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that multiplication works the same way on both assembly-optimized and pure Go
|
||||
// implementation.
|
||||
func TestGFpMul(t *testing.T) {
|
||||
a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
|
||||
b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef}
|
||||
w := &gfP{0xcbcbd377f7ad22d3, 0x3b89ba5d849379bf, 0x87b61627bd38b6d2, 0xc44052a2a0e654b2}
|
||||
h := &gfP{}
|
||||
|
||||
gfpMul(h, a, b)
|
||||
if *h != *w {
|
||||
t.Errorf("multiplication mismatch: have %#x, want %#x", *h, *w)
|
||||
}
|
||||
}
|
||||
73
crypto/bn256/cloudflare/main_test.go
Normal file
73
crypto/bn256/cloudflare/main_test.go
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
func TestRandomG2Marshal(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
n, g2, err := RandomG2(rand.Reader)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
t.Logf("%d: %x\n", n, g2.Marshal())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPairings(t *testing.T) {
|
||||
a1 := new(G1).ScalarBaseMult(bigFromBase10("1"))
|
||||
a2 := new(G1).ScalarBaseMult(bigFromBase10("2"))
|
||||
a37 := new(G1).ScalarBaseMult(bigFromBase10("37"))
|
||||
an1 := new(G1).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616"))
|
||||
|
||||
b0 := new(G2).ScalarBaseMult(bigFromBase10("0"))
|
||||
b1 := new(G2).ScalarBaseMult(bigFromBase10("1"))
|
||||
b2 := new(G2).ScalarBaseMult(bigFromBase10("2"))
|
||||
b27 := new(G2).ScalarBaseMult(bigFromBase10("27"))
|
||||
b999 := new(G2).ScalarBaseMult(bigFromBase10("999"))
|
||||
bn1 := new(G2).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616"))
|
||||
|
||||
p1 := Pair(a1, b1)
|
||||
pn1 := Pair(a1, bn1)
|
||||
np1 := Pair(an1, b1)
|
||||
if pn1.String() != np1.String() {
|
||||
t.Error("Pairing mismatch: e(a, -b) != e(-a, b)")
|
||||
}
|
||||
if !PairingCheck([]*G1{a1, an1}, []*G2{b1, b1}) {
|
||||
t.Error("MultiAte check gave false negative!")
|
||||
}
|
||||
p0 := new(GT).Add(p1, pn1)
|
||||
p0_2 := Pair(a1, b0)
|
||||
if p0.String() != p0_2.String() {
|
||||
t.Error("Pairing mismatch: e(a, b) * e(a, -b) != 1")
|
||||
}
|
||||
p0_3 := new(GT).ScalarMult(p1, bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617"))
|
||||
if p0.String() != p0_3.String() {
|
||||
t.Error("Pairing mismatch: e(a, b) has wrong order")
|
||||
}
|
||||
p2 := Pair(a2, b1)
|
||||
p2_2 := Pair(a1, b2)
|
||||
p2_3 := new(GT).ScalarMult(p1, bigFromBase10("2"))
|
||||
if p2.String() != p2_2.String() {
|
||||
t.Error("Pairing mismatch: e(a, b * 2) != e(a * 2, b)")
|
||||
}
|
||||
if p2.String() != p2_3.String() {
|
||||
t.Error("Pairing mismatch: e(a, b * 2) != e(a, b) ** 2")
|
||||
}
|
||||
if p2.String() == p1.String() {
|
||||
t.Error("Pairing is degenerate!")
|
||||
}
|
||||
if PairingCheck([]*G1{a1, a1}, []*G2{b1, b1}) {
|
||||
t.Error("MultiAte check gave false positive!")
|
||||
}
|
||||
p999 := Pair(a37, b27)
|
||||
p999_2 := Pair(a1, b999)
|
||||
if p999.String() != p999_2.String() {
|
||||
t.Error("Pairing mismatch: e(a * 37, b * 27) != e(a, b * 999)")
|
||||
}
|
||||
}
|
||||
181
crypto/bn256/cloudflare/mul.h
Normal file
181
crypto/bn256/cloudflare/mul.h
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
#define mul(a0,a1,a2,a3, rb, stack) \
|
||||
MOVQ a0, AX \
|
||||
MULQ 0+rb \
|
||||
MOVQ AX, R8 \
|
||||
MOVQ DX, R9 \
|
||||
MOVQ a0, AX \
|
||||
MULQ 8+rb \
|
||||
ADDQ AX, R9 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R10 \
|
||||
MOVQ a0, AX \
|
||||
MULQ 16+rb \
|
||||
ADDQ AX, R10 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R11 \
|
||||
MOVQ a0, AX \
|
||||
MULQ 24+rb \
|
||||
ADDQ AX, R11 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R12 \
|
||||
\
|
||||
storeBlock(R8,R9,R10,R11, 0+stack) \
|
||||
MOVQ R12, 32+stack \
|
||||
\
|
||||
MOVQ a1, AX \
|
||||
MULQ 0+rb \
|
||||
MOVQ AX, R8 \
|
||||
MOVQ DX, R9 \
|
||||
MOVQ a1, AX \
|
||||
MULQ 8+rb \
|
||||
ADDQ AX, R9 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R10 \
|
||||
MOVQ a1, AX \
|
||||
MULQ 16+rb \
|
||||
ADDQ AX, R10 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R11 \
|
||||
MOVQ a1, AX \
|
||||
MULQ 24+rb \
|
||||
ADDQ AX, R11 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R12 \
|
||||
\
|
||||
ADDQ 8+stack, R8 \
|
||||
ADCQ 16+stack, R9 \
|
||||
ADCQ 24+stack, R10 \
|
||||
ADCQ 32+stack, R11 \
|
||||
ADCQ $0, R12 \
|
||||
storeBlock(R8,R9,R10,R11, 8+stack) \
|
||||
MOVQ R12, 40+stack \
|
||||
\
|
||||
MOVQ a2, AX \
|
||||
MULQ 0+rb \
|
||||
MOVQ AX, R8 \
|
||||
MOVQ DX, R9 \
|
||||
MOVQ a2, AX \
|
||||
MULQ 8+rb \
|
||||
ADDQ AX, R9 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R10 \
|
||||
MOVQ a2, AX \
|
||||
MULQ 16+rb \
|
||||
ADDQ AX, R10 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R11 \
|
||||
MOVQ a2, AX \
|
||||
MULQ 24+rb \
|
||||
ADDQ AX, R11 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R12 \
|
||||
\
|
||||
ADDQ 16+stack, R8 \
|
||||
ADCQ 24+stack, R9 \
|
||||
ADCQ 32+stack, R10 \
|
||||
ADCQ 40+stack, R11 \
|
||||
ADCQ $0, R12 \
|
||||
storeBlock(R8,R9,R10,R11, 16+stack) \
|
||||
MOVQ R12, 48+stack \
|
||||
\
|
||||
MOVQ a3, AX \
|
||||
MULQ 0+rb \
|
||||
MOVQ AX, R8 \
|
||||
MOVQ DX, R9 \
|
||||
MOVQ a3, AX \
|
||||
MULQ 8+rb \
|
||||
ADDQ AX, R9 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R10 \
|
||||
MOVQ a3, AX \
|
||||
MULQ 16+rb \
|
||||
ADDQ AX, R10 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R11 \
|
||||
MOVQ a3, AX \
|
||||
MULQ 24+rb \
|
||||
ADDQ AX, R11 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R12 \
|
||||
\
|
||||
ADDQ 24+stack, R8 \
|
||||
ADCQ 32+stack, R9 \
|
||||
ADCQ 40+stack, R10 \
|
||||
ADCQ 48+stack, R11 \
|
||||
ADCQ $0, R12 \
|
||||
storeBlock(R8,R9,R10,R11, 24+stack) \
|
||||
MOVQ R12, 56+stack
|
||||
|
||||
#define gfpReduce(stack) \
|
||||
\ // m = (T * N') mod R, store m in R8:R9:R10:R11
|
||||
MOVQ ·np+0(SB), AX \
|
||||
MULQ 0+stack \
|
||||
MOVQ AX, R8 \
|
||||
MOVQ DX, R9 \
|
||||
MOVQ ·np+0(SB), AX \
|
||||
MULQ 8+stack \
|
||||
ADDQ AX, R9 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R10 \
|
||||
MOVQ ·np+0(SB), AX \
|
||||
MULQ 16+stack \
|
||||
ADDQ AX, R10 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R11 \
|
||||
MOVQ ·np+0(SB), AX \
|
||||
MULQ 24+stack \
|
||||
ADDQ AX, R11 \
|
||||
\
|
||||
MOVQ ·np+8(SB), AX \
|
||||
MULQ 0+stack \
|
||||
MOVQ AX, R12 \
|
||||
MOVQ DX, R13 \
|
||||
MOVQ ·np+8(SB), AX \
|
||||
MULQ 8+stack \
|
||||
ADDQ AX, R13 \
|
||||
ADCQ $0, DX \
|
||||
MOVQ DX, R14 \
|
||||
MOVQ ·np+8(SB), AX \
|
||||
MULQ 16+stack \
|
||||
ADDQ AX, R14 \
|
||||
\
|
||||
ADDQ R12, R9 \
|
||||
ADCQ R13, R10 \
|
||||
ADCQ R14, R11 \
|
||||
\
|
||||
MOVQ ·np+16(SB), AX \
|
||||
MULQ 0+stack \
|
||||
MOVQ AX, R12 \
|
||||
MOVQ DX, R13 \
|
||||
MOVQ ·np+16(SB), AX \
|
||||
MULQ 8+stack \
|
||||
ADDQ AX, R13 \
|
||||
\
|
||||
ADDQ R12, R10 \
|
||||
ADCQ R13, R11 \
|
||||
\
|
||||
MOVQ ·np+24(SB), AX \
|
||||
MULQ 0+stack \
|
||||
ADDQ AX, R11 \
|
||||
\
|
||||
storeBlock(R8,R9,R10,R11, 64+stack) \
|
||||
\
|
||||
\ // m * N
|
||||
mul(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64+stack, 96+stack) \
|
||||
\
|
||||
\ // Add the 512-bit intermediate to m*N
|
||||
loadBlock(96+stack, R8,R9,R10,R11) \
|
||||
loadBlock(128+stack, R12,R13,R14,R15) \
|
||||
\
|
||||
MOVQ $0, AX \
|
||||
ADDQ 0+stack, R8 \
|
||||
ADCQ 8+stack, R9 \
|
||||
ADCQ 16+stack, R10 \
|
||||
ADCQ 24+stack, R11 \
|
||||
ADCQ 32+stack, R12 \
|
||||
ADCQ 40+stack, R13 \
|
||||
ADCQ 48+stack, R14 \
|
||||
ADCQ 56+stack, R15 \
|
||||
ADCQ $0, AX \
|
||||
\
|
||||
gfpCarry(R12,R13,R14,R15,AX, R8,R9,R10,R11,BX)
|
||||
112
crypto/bn256/cloudflare/mul_bmi2.h
Normal file
112
crypto/bn256/cloudflare/mul_bmi2.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
#define mulBMI2(a0,a1,a2,a3, rb) \
|
||||
MOVQ a0, DX \
|
||||
MOVQ $0, R13 \
|
||||
MULXQ 0+rb, R8, R9 \
|
||||
MULXQ 8+rb, AX, R10 \
|
||||
ADDQ AX, R9 \
|
||||
MULXQ 16+rb, AX, R11 \
|
||||
ADCQ AX, R10 \
|
||||
MULXQ 24+rb, AX, R12 \
|
||||
ADCQ AX, R11 \
|
||||
ADCQ $0, R12 \
|
||||
ADCQ $0, R13 \
|
||||
\
|
||||
MOVQ a1, DX \
|
||||
MOVQ $0, R14 \
|
||||
MULXQ 0+rb, AX, BX \
|
||||
ADDQ AX, R9 \
|
||||
ADCQ BX, R10 \
|
||||
MULXQ 16+rb, AX, BX \
|
||||
ADCQ AX, R11 \
|
||||
ADCQ BX, R12 \
|
||||
ADCQ $0, R13 \
|
||||
MULXQ 8+rb, AX, BX \
|
||||
ADDQ AX, R10 \
|
||||
ADCQ BX, R11 \
|
||||
MULXQ 24+rb, AX, BX \
|
||||
ADCQ AX, R12 \
|
||||
ADCQ BX, R13 \
|
||||
ADCQ $0, R14 \
|
||||
\
|
||||
MOVQ a2, DX \
|
||||
MOVQ $0, R15 \
|
||||
MULXQ 0+rb, AX, BX \
|
||||
ADDQ AX, R10 \
|
||||
ADCQ BX, R11 \
|
||||
MULXQ 16+rb, AX, BX \
|
||||
ADCQ AX, R12 \
|
||||
ADCQ BX, R13 \
|
||||
ADCQ $0, R14 \
|
||||
MULXQ 8+rb, AX, BX \
|
||||
ADDQ AX, R11 \
|
||||
ADCQ BX, R12 \
|
||||
MULXQ 24+rb, AX, BX \
|
||||
ADCQ AX, R13 \
|
||||
ADCQ BX, R14 \
|
||||
ADCQ $0, R15 \
|
||||
\
|
||||
MOVQ a3, DX \
|
||||
MULXQ 0+rb, AX, BX \
|
||||
ADDQ AX, R11 \
|
||||
ADCQ BX, R12 \
|
||||
MULXQ 16+rb, AX, BX \
|
||||
ADCQ AX, R13 \
|
||||
ADCQ BX, R14 \
|
||||
ADCQ $0, R15 \
|
||||
MULXQ 8+rb, AX, BX \
|
||||
ADDQ AX, R12 \
|
||||
ADCQ BX, R13 \
|
||||
MULXQ 24+rb, AX, BX \
|
||||
ADCQ AX, R14 \
|
||||
ADCQ BX, R15
|
||||
|
||||
#define gfpReduceBMI2() \
|
||||
\ // m = (T * N') mod R, store m in R8:R9:R10:R11
|
||||
MOVQ ·np+0(SB), DX \
|
||||
MULXQ 0(SP), R8, R9 \
|
||||
MULXQ 8(SP), AX, R10 \
|
||||
ADDQ AX, R9 \
|
||||
MULXQ 16(SP), AX, R11 \
|
||||
ADCQ AX, R10 \
|
||||
MULXQ 24(SP), AX, BX \
|
||||
ADCQ AX, R11 \
|
||||
\
|
||||
MOVQ ·np+8(SB), DX \
|
||||
MULXQ 0(SP), AX, BX \
|
||||
ADDQ AX, R9 \
|
||||
ADCQ BX, R10 \
|
||||
MULXQ 16(SP), AX, BX \
|
||||
ADCQ AX, R11 \
|
||||
MULXQ 8(SP), AX, BX \
|
||||
ADDQ AX, R10 \
|
||||
ADCQ BX, R11 \
|
||||
\
|
||||
MOVQ ·np+16(SB), DX \
|
||||
MULXQ 0(SP), AX, BX \
|
||||
ADDQ AX, R10 \
|
||||
ADCQ BX, R11 \
|
||||
MULXQ 8(SP), AX, BX \
|
||||
ADDQ AX, R11 \
|
||||
\
|
||||
MOVQ ·np+24(SB), DX \
|
||||
MULXQ 0(SP), AX, BX \
|
||||
ADDQ AX, R11 \
|
||||
\
|
||||
storeBlock(R8,R9,R10,R11, 64(SP)) \
|
||||
\
|
||||
\ // m * N
|
||||
mulBMI2(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64(SP)) \
|
||||
\
|
||||
\ // Add the 512-bit intermediate to m*N
|
||||
MOVQ $0, AX \
|
||||
ADDQ 0(SP), R8 \
|
||||
ADCQ 8(SP), R9 \
|
||||
ADCQ 16(SP), R10 \
|
||||
ADCQ 24(SP), R11 \
|
||||
ADCQ 32(SP), R12 \
|
||||
ADCQ 40(SP), R13 \
|
||||
ADCQ 48(SP), R14 \
|
||||
ADCQ 56(SP), R15 \
|
||||
ADCQ $0, AX \
|
||||
\
|
||||
gfpCarry(R12,R13,R14,R15,AX, R8,R9,R10,R11,BX)
|
||||
271
crypto/bn256/cloudflare/optate.go
Normal file
271
crypto/bn256/cloudflare/optate.go
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
package bn256
|
||||
|
||||
func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2) (a, b, c *gfP2, rOut *twistPoint) {
|
||||
// See the mixed addition algorithm from "Faster Computation of the
|
||||
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
|
||||
B := (&gfP2{}).Mul(&p.x, &r.t)
|
||||
|
||||
D := (&gfP2{}).Add(&p.y, &r.z)
|
||||
D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t)
|
||||
|
||||
H := (&gfP2{}).Sub(B, &r.x)
|
||||
I := (&gfP2{}).Square(H)
|
||||
|
||||
E := (&gfP2{}).Add(I, I)
|
||||
E.Add(E, E)
|
||||
|
||||
J := (&gfP2{}).Mul(H, E)
|
||||
|
||||
L1 := (&gfP2{}).Sub(D, &r.y)
|
||||
L1.Sub(L1, &r.y)
|
||||
|
||||
V := (&gfP2{}).Mul(&r.x, E)
|
||||
|
||||
rOut = &twistPoint{}
|
||||
rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V)
|
||||
|
||||
rOut.z.Add(&r.z, H).Square(&rOut.z).Sub(&rOut.z, &r.t).Sub(&rOut.z, I)
|
||||
|
||||
t := (&gfP2{}).Sub(V, &rOut.x)
|
||||
t.Mul(t, L1)
|
||||
t2 := (&gfP2{}).Mul(&r.y, J)
|
||||
t2.Add(t2, t2)
|
||||
rOut.y.Sub(t, t2)
|
||||
|
||||
rOut.t.Square(&rOut.z)
|
||||
|
||||
t.Add(&p.y, &rOut.z).Square(t).Sub(t, r2).Sub(t, &rOut.t)
|
||||
|
||||
t2.Mul(L1, &p.x)
|
||||
t2.Add(t2, t2)
|
||||
a = (&gfP2{}).Sub(t2, t)
|
||||
|
||||
c = (&gfP2{}).MulScalar(&rOut.z, &q.y)
|
||||
c.Add(c, c)
|
||||
|
||||
b = (&gfP2{}).Neg(L1)
|
||||
b.MulScalar(b, &q.x).Add(b, b)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func lineFunctionDouble(r *twistPoint, q *curvePoint) (a, b, c *gfP2, rOut *twistPoint) {
|
||||
// See the doubling algorithm for a=0 from "Faster Computation of the
|
||||
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
|
||||
A := (&gfP2{}).Square(&r.x)
|
||||
B := (&gfP2{}).Square(&r.y)
|
||||
C := (&gfP2{}).Square(B)
|
||||
|
||||
D := (&gfP2{}).Add(&r.x, B)
|
||||
D.Square(D).Sub(D, A).Sub(D, C).Add(D, D)
|
||||
|
||||
E := (&gfP2{}).Add(A, A)
|
||||
E.Add(E, A)
|
||||
|
||||
G := (&gfP2{}).Square(E)
|
||||
|
||||
rOut = &twistPoint{}
|
||||
rOut.x.Sub(G, D).Sub(&rOut.x, D)
|
||||
|
||||
rOut.z.Add(&r.y, &r.z).Square(&rOut.z).Sub(&rOut.z, B).Sub(&rOut.z, &r.t)
|
||||
|
||||
rOut.y.Sub(D, &rOut.x).Mul(&rOut.y, E)
|
||||
t := (&gfP2{}).Add(C, C)
|
||||
t.Add(t, t).Add(t, t)
|
||||
rOut.y.Sub(&rOut.y, t)
|
||||
|
||||
rOut.t.Square(&rOut.z)
|
||||
|
||||
t.Mul(E, &r.t).Add(t, t)
|
||||
b = (&gfP2{}).Neg(t)
|
||||
b.MulScalar(b, &q.x)
|
||||
|
||||
a = (&gfP2{}).Add(&r.x, E)
|
||||
a.Square(a).Sub(a, A).Sub(a, G)
|
||||
t.Add(B, B).Add(t, t)
|
||||
a.Sub(a, t)
|
||||
|
||||
c = (&gfP2{}).Mul(&rOut.z, &r.t)
|
||||
c.Add(c, c).MulScalar(c, &q.y)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func mulLine(ret *gfP12, a, b, c *gfP2) {
|
||||
a2 := &gfP6{}
|
||||
a2.y.Set(a)
|
||||
a2.z.Set(b)
|
||||
a2.Mul(a2, &ret.x)
|
||||
t3 := (&gfP6{}).MulScalar(&ret.y, c)
|
||||
|
||||
t := (&gfP2{}).Add(b, c)
|
||||
t2 := &gfP6{}
|
||||
t2.y.Set(a)
|
||||
t2.z.Set(t)
|
||||
ret.x.Add(&ret.x, &ret.y)
|
||||
|
||||
ret.y.Set(t3)
|
||||
|
||||
ret.x.Mul(&ret.x, t2).Sub(&ret.x, a2).Sub(&ret.x, &ret.y)
|
||||
a2.MulTau(a2)
|
||||
ret.y.Add(&ret.y, a2)
|
||||
}
|
||||
|
||||
// sixuPlus2NAF is 6u+2 in non-adjacent form.
|
||||
var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0,
|
||||
0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1,
|
||||
1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1,
|
||||
1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1}
|
||||
|
||||
// miller implements the Miller loop for calculating the Optimal Ate pairing.
|
||||
// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf
|
||||
func miller(q *twistPoint, p *curvePoint) *gfP12 {
|
||||
ret := (&gfP12{}).SetOne()
|
||||
|
||||
aAffine := &twistPoint{}
|
||||
aAffine.Set(q)
|
||||
aAffine.MakeAffine()
|
||||
|
||||
bAffine := &curvePoint{}
|
||||
bAffine.Set(p)
|
||||
bAffine.MakeAffine()
|
||||
|
||||
minusA := &twistPoint{}
|
||||
minusA.Neg(aAffine)
|
||||
|
||||
r := &twistPoint{}
|
||||
r.Set(aAffine)
|
||||
|
||||
r2 := (&gfP2{}).Square(&aAffine.y)
|
||||
|
||||
for i := len(sixuPlus2NAF) - 1; i > 0; i-- {
|
||||
a, b, c, newR := lineFunctionDouble(r, bAffine)
|
||||
if i != len(sixuPlus2NAF)-1 {
|
||||
ret.Square(ret)
|
||||
}
|
||||
|
||||
mulLine(ret, a, b, c)
|
||||
r = newR
|
||||
|
||||
switch sixuPlus2NAF[i-1] {
|
||||
case 1:
|
||||
a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2)
|
||||
case -1:
|
||||
a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
mulLine(ret, a, b, c)
|
||||
r = newR
|
||||
}
|
||||
|
||||
// In order to calculate Q1 we have to convert q from the sextic twist
|
||||
// to the full GF(p^12) group, apply the Frobenius there, and convert
|
||||
// back.
|
||||
//
|
||||
// The twist isomorphism is (x', y') -> (xω², yω³). If we consider just
|
||||
// x for a moment, then after applying the Frobenius, we have x̄ω^(2p)
|
||||
// where x̄ is the conjugate of x. If we are going to apply the inverse
|
||||
// isomorphism we need a value with a single coefficient of ω² so we
|
||||
// rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of
|
||||
// p, 2p-2 is a multiple of six. Therefore we can rewrite as
|
||||
// x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the
|
||||
// ω².
|
||||
//
|
||||
// A similar argument can be made for the y value.
|
||||
|
||||
q1 := &twistPoint{}
|
||||
q1.x.Conjugate(&aAffine.x).Mul(&q1.x, xiToPMinus1Over3)
|
||||
q1.y.Conjugate(&aAffine.y).Mul(&q1.y, xiToPMinus1Over2)
|
||||
q1.z.SetOne()
|
||||
q1.t.SetOne()
|
||||
|
||||
// For Q2 we are applying the p² Frobenius. The two conjugations cancel
|
||||
// out and we are left only with the factors from the isomorphism. In
|
||||
// the case of x, we end up with a pure number which is why
|
||||
// xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We
|
||||
// ignore this to end up with -Q2.
|
||||
|
||||
minusQ2 := &twistPoint{}
|
||||
minusQ2.x.MulScalar(&aAffine.x, xiToPSquaredMinus1Over3)
|
||||
minusQ2.y.Set(&aAffine.y)
|
||||
minusQ2.z.SetOne()
|
||||
minusQ2.t.SetOne()
|
||||
|
||||
r2.Square(&q1.y)
|
||||
a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2)
|
||||
mulLine(ret, a, b, c)
|
||||
r = newR
|
||||
|
||||
r2.Square(&minusQ2.y)
|
||||
a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2)
|
||||
mulLine(ret, a, b, c)
|
||||
r = newR
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// finalExponentiation computes the (p¹²-1)/Order-th power of an element of
|
||||
// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from
|
||||
// http://cryptojedi.org/papers/dclxvi-20100714.pdf)
|
||||
func finalExponentiation(in *gfP12) *gfP12 {
|
||||
t1 := &gfP12{}
|
||||
|
||||
// This is the p^6-Frobenius
|
||||
t1.x.Neg(&in.x)
|
||||
t1.y.Set(&in.y)
|
||||
|
||||
inv := &gfP12{}
|
||||
inv.Invert(in)
|
||||
t1.Mul(t1, inv)
|
||||
|
||||
t2 := (&gfP12{}).FrobeniusP2(t1)
|
||||
t1.Mul(t1, t2)
|
||||
|
||||
fp := (&gfP12{}).Frobenius(t1)
|
||||
fp2 := (&gfP12{}).FrobeniusP2(t1)
|
||||
fp3 := (&gfP12{}).Frobenius(fp2)
|
||||
|
||||
fu := (&gfP12{}).Exp(t1, u)
|
||||
fu2 := (&gfP12{}).Exp(fu, u)
|
||||
fu3 := (&gfP12{}).Exp(fu2, u)
|
||||
|
||||
y3 := (&gfP12{}).Frobenius(fu)
|
||||
fu2p := (&gfP12{}).Frobenius(fu2)
|
||||
fu3p := (&gfP12{}).Frobenius(fu3)
|
||||
y2 := (&gfP12{}).FrobeniusP2(fu2)
|
||||
|
||||
y0 := &gfP12{}
|
||||
y0.Mul(fp, fp2).Mul(y0, fp3)
|
||||
|
||||
y1 := (&gfP12{}).Conjugate(t1)
|
||||
y5 := (&gfP12{}).Conjugate(fu2)
|
||||
y3.Conjugate(y3)
|
||||
y4 := (&gfP12{}).Mul(fu, fu2p)
|
||||
y4.Conjugate(y4)
|
||||
|
||||
y6 := (&gfP12{}).Mul(fu3, fu3p)
|
||||
y6.Conjugate(y6)
|
||||
|
||||
t0 := (&gfP12{}).Square(y6)
|
||||
t0.Mul(t0, y4).Mul(t0, y5)
|
||||
t1.Mul(y3, y5).Mul(t1, t0)
|
||||
t0.Mul(t0, y2)
|
||||
t1.Square(t1).Mul(t1, t0).Square(t1)
|
||||
t0.Mul(t1, y1)
|
||||
t1.Mul(t1, y0)
|
||||
t0.Square(t0).Mul(t0, t1)
|
||||
|
||||
return t0
|
||||
}
|
||||
|
||||
func optimalAte(a *twistPoint, b *curvePoint) *gfP12 {
|
||||
e := miller(a, b)
|
||||
ret := finalExponentiation(e)
|
||||
|
||||
if a.IsInfinity() || b.IsInfinity() {
|
||||
ret.SetOne()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
204
crypto/bn256/cloudflare/twist.go
Normal file
204
crypto/bn256/cloudflare/twist.go
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
package bn256
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are
|
||||
// kept in Jacobian form and t=z² when valid. The group G₂ is the set of
|
||||
// n-torsion points of this curve over GF(p²) (where n = Order)
|
||||
type twistPoint struct {
|
||||
x, y, z, t gfP2
|
||||
}
|
||||
|
||||
var twistB = &gfP2{
|
||||
gfP{0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d},
|
||||
gfP{0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d},
|
||||
}
|
||||
|
||||
// twistGen is the generator of group G₂.
|
||||
var twistGen = &twistPoint{
|
||||
gfP2{
|
||||
gfP{0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b},
|
||||
gfP{0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b},
|
||||
},
|
||||
gfP2{
|
||||
gfP{0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482},
|
||||
gfP{0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206},
|
||||
},
|
||||
gfP2{*newGFp(0), *newGFp(1)},
|
||||
gfP2{*newGFp(0), *newGFp(1)},
|
||||
}
|
||||
|
||||
func (c *twistPoint) String() string {
|
||||
c.MakeAffine()
|
||||
x, y := gfP2Decode(&c.x), gfP2Decode(&c.y)
|
||||
return "(" + x.String() + ", " + y.String() + ")"
|
||||
}
|
||||
|
||||
func (c *twistPoint) Set(a *twistPoint) {
|
||||
c.x.Set(&a.x)
|
||||
c.y.Set(&a.y)
|
||||
c.z.Set(&a.z)
|
||||
c.t.Set(&a.t)
|
||||
}
|
||||
|
||||
// IsOnCurve returns true iff c is on the curve.
|
||||
func (c *twistPoint) IsOnCurve() bool {
|
||||
c.MakeAffine()
|
||||
if c.IsInfinity() {
|
||||
return true
|
||||
}
|
||||
|
||||
y2, x3 := &gfP2{}, &gfP2{}
|
||||
y2.Square(&c.y)
|
||||
x3.Square(&c.x).Mul(x3, &c.x).Add(x3, twistB)
|
||||
|
||||
if *y2 != *x3 {
|
||||
return false
|
||||
}
|
||||
cneg := &twistPoint{}
|
||||
cneg.Mul(c, Order)
|
||||
return cneg.z.IsZero()
|
||||
}
|
||||
|
||||
func (c *twistPoint) SetInfinity() {
|
||||
c.x.SetZero()
|
||||
c.y.SetOne()
|
||||
c.z.SetZero()
|
||||
c.t.SetZero()
|
||||
}
|
||||
|
||||
func (c *twistPoint) IsInfinity() bool {
|
||||
return c.z.IsZero()
|
||||
}
|
||||
|
||||
func (c *twistPoint) Add(a, b *twistPoint) {
|
||||
// For additional comments, see the same function in curve.go.
|
||||
|
||||
if a.IsInfinity() {
|
||||
c.Set(b)
|
||||
return
|
||||
}
|
||||
if b.IsInfinity() {
|
||||
c.Set(a)
|
||||
return
|
||||
}
|
||||
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
|
||||
z12 := (&gfP2{}).Square(&a.z)
|
||||
z22 := (&gfP2{}).Square(&b.z)
|
||||
u1 := (&gfP2{}).Mul(&a.x, z22)
|
||||
u2 := (&gfP2{}).Mul(&b.x, z12)
|
||||
|
||||
t := (&gfP2{}).Mul(&b.z, z22)
|
||||
s1 := (&gfP2{}).Mul(&a.y, t)
|
||||
|
||||
t.Mul(&a.z, z12)
|
||||
s2 := (&gfP2{}).Mul(&b.y, t)
|
||||
|
||||
h := (&gfP2{}).Sub(u2, u1)
|
||||
xEqual := h.IsZero()
|
||||
|
||||
t.Add(h, h)
|
||||
i := (&gfP2{}).Square(t)
|
||||
j := (&gfP2{}).Mul(h, i)
|
||||
|
||||
t.Sub(s2, s1)
|
||||
yEqual := t.IsZero()
|
||||
if xEqual && yEqual {
|
||||
c.Double(a)
|
||||
return
|
||||
}
|
||||
r := (&gfP2{}).Add(t, t)
|
||||
|
||||
v := (&gfP2{}).Mul(u1, i)
|
||||
|
||||
t4 := (&gfP2{}).Square(r)
|
||||
t.Add(v, v)
|
||||
t6 := (&gfP2{}).Sub(t4, j)
|
||||
c.x.Sub(t6, t)
|
||||
|
||||
t.Sub(v, &c.x) // t7
|
||||
t4.Mul(s1, j) // t8
|
||||
t6.Add(t4, t4) // t9
|
||||
t4.Mul(r, t) // t10
|
||||
c.y.Sub(t4, t6)
|
||||
|
||||
t.Add(&a.z, &b.z) // t11
|
||||
t4.Square(t) // t12
|
||||
t.Sub(t4, z12) // t13
|
||||
t4.Sub(t, z22) // t14
|
||||
c.z.Mul(t4, h)
|
||||
}
|
||||
|
||||
func (c *twistPoint) Double(a *twistPoint) {
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
|
||||
A := (&gfP2{}).Square(&a.x)
|
||||
B := (&gfP2{}).Square(&a.y)
|
||||
C := (&gfP2{}).Square(B)
|
||||
|
||||
t := (&gfP2{}).Add(&a.x, B)
|
||||
t2 := (&gfP2{}).Square(t)
|
||||
t.Sub(t2, A)
|
||||
t2.Sub(t, C)
|
||||
d := (&gfP2{}).Add(t2, t2)
|
||||
t.Add(A, A)
|
||||
e := (&gfP2{}).Add(t, A)
|
||||
f := (&gfP2{}).Square(e)
|
||||
|
||||
t.Add(d, d)
|
||||
c.x.Sub(f, t)
|
||||
|
||||
t.Add(C, C)
|
||||
t2.Add(t, t)
|
||||
t.Add(t2, t2)
|
||||
c.y.Sub(d, &c.x)
|
||||
t2.Mul(e, &c.y)
|
||||
c.y.Sub(t2, t)
|
||||
|
||||
t.Mul(&a.y, &a.z)
|
||||
c.z.Add(t, t)
|
||||
}
|
||||
|
||||
func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) {
|
||||
sum, t := &twistPoint{}, &twistPoint{}
|
||||
|
||||
for i := scalar.BitLen(); i >= 0; i-- {
|
||||
t.Double(sum)
|
||||
if scalar.Bit(i) != 0 {
|
||||
sum.Add(t, a)
|
||||
} else {
|
||||
sum.Set(t)
|
||||
}
|
||||
}
|
||||
|
||||
c.Set(sum)
|
||||
}
|
||||
|
||||
func (c *twistPoint) MakeAffine() {
|
||||
if c.z.IsOne() {
|
||||
return
|
||||
} else if c.z.IsZero() {
|
||||
c.x.SetZero()
|
||||
c.y.SetOne()
|
||||
c.t.SetZero()
|
||||
return
|
||||
}
|
||||
|
||||
zInv := (&gfP2{}).Invert(&c.z)
|
||||
t := (&gfP2{}).Mul(&c.y, zInv)
|
||||
zInv2 := (&gfP2{}).Square(zInv)
|
||||
c.y.Mul(t, zInv2)
|
||||
t.Mul(&c.x, zInv2)
|
||||
c.x.Set(t)
|
||||
c.z.SetOne()
|
||||
c.t.SetOne()
|
||||
}
|
||||
|
||||
func (c *twistPoint) Neg(a *twistPoint) {
|
||||
c.x.Set(&a.x)
|
||||
c.y.Neg(&a.y)
|
||||
c.z.Set(&a.z)
|
||||
c.t.SetZero()
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ package bn256
|
|||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
|
@ -115,21 +116,25 @@ func (n *G1) Marshal() []byte {
|
|||
|
||||
// Unmarshal sets e to the result of converting the output of Marshal back into
|
||||
// a group element and then returns e.
|
||||
func (e *G1) Unmarshal(m []byte) (*G1, bool) {
|
||||
func (e *G1) Unmarshal(m []byte) ([]byte, error) {
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
|
||||
if len(m) != 2*numBytes {
|
||||
return nil, false
|
||||
return nil, errors.New("bn256: not enough data")
|
||||
}
|
||||
|
||||
// Unmarshal the points and check their caps
|
||||
if e.p == nil {
|
||||
e.p = newCurvePoint(nil)
|
||||
}
|
||||
|
||||
e.p.x.SetBytes(m[0*numBytes : 1*numBytes])
|
||||
if e.p.x.Cmp(P) >= 0 {
|
||||
return nil, errors.New("bn256: coordinate exceeds modulus")
|
||||
}
|
||||
e.p.y.SetBytes(m[1*numBytes : 2*numBytes])
|
||||
|
||||
if e.p.y.Cmp(P) >= 0 {
|
||||
return nil, errors.New("bn256: coordinate exceeds modulus")
|
||||
}
|
||||
// Ensure the point is on the curve
|
||||
if e.p.x.Sign() == 0 && e.p.y.Sign() == 0 {
|
||||
// This is the point at infinity.
|
||||
e.p.y.SetInt64(1)
|
||||
|
|
@ -140,11 +145,10 @@ func (e *G1) Unmarshal(m []byte) (*G1, bool) {
|
|||
e.p.t.SetInt64(1)
|
||||
|
||||
if !e.p.IsOnCurve() {
|
||||
return nil, false
|
||||
return nil, errors.New("bn256: malformed point")
|
||||
}
|
||||
}
|
||||
|
||||
return e, true
|
||||
return m[2*numBytes:], nil
|
||||
}
|
||||
|
||||
// G2 is an abstract cyclic group. The zero value is suitable for use as the
|
||||
|
|
@ -233,23 +237,33 @@ func (n *G2) Marshal() []byte {
|
|||
|
||||
// Unmarshal sets e to the result of converting the output of Marshal back into
|
||||
// a group element and then returns e.
|
||||
func (e *G2) Unmarshal(m []byte) (*G2, bool) {
|
||||
func (e *G2) Unmarshal(m []byte) ([]byte, error) {
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
|
||||
if len(m) != 4*numBytes {
|
||||
return nil, false
|
||||
return nil, errors.New("bn256: not enough data")
|
||||
}
|
||||
|
||||
// Unmarshal the points and check their caps
|
||||
if e.p == nil {
|
||||
e.p = newTwistPoint(nil)
|
||||
}
|
||||
|
||||
e.p.x.x.SetBytes(m[0*numBytes : 1*numBytes])
|
||||
if e.p.x.x.Cmp(P) >= 0 {
|
||||
return nil, errors.New("bn256: coordinate exceeds modulus")
|
||||
}
|
||||
e.p.x.y.SetBytes(m[1*numBytes : 2*numBytes])
|
||||
if e.p.x.y.Cmp(P) >= 0 {
|
||||
return nil, errors.New("bn256: coordinate exceeds modulus")
|
||||
}
|
||||
e.p.y.x.SetBytes(m[2*numBytes : 3*numBytes])
|
||||
if e.p.y.x.Cmp(P) >= 0 {
|
||||
return nil, errors.New("bn256: coordinate exceeds modulus")
|
||||
}
|
||||
e.p.y.y.SetBytes(m[3*numBytes : 4*numBytes])
|
||||
|
||||
if e.p.y.y.Cmp(P) >= 0 {
|
||||
return nil, errors.New("bn256: coordinate exceeds modulus")
|
||||
}
|
||||
// Ensure the point is on the curve
|
||||
if e.p.x.x.Sign() == 0 &&
|
||||
e.p.x.y.Sign() == 0 &&
|
||||
e.p.y.x.Sign() == 0 &&
|
||||
|
|
@ -263,11 +277,10 @@ func (e *G2) Unmarshal(m []byte) (*G2, bool) {
|
|||
e.p.t.SetOne()
|
||||
|
||||
if !e.p.IsOnCurve() {
|
||||
return nil, false
|
||||
return nil, errors.New("bn256: malformed point")
|
||||
}
|
||||
}
|
||||
|
||||
return e, true
|
||||
return m[4*numBytes:], nil
|
||||
}
|
||||
|
||||
// GT is an abstract cyclic group. The zero value is suitable for use as the
|
||||
|
|
@ -219,15 +219,16 @@ func TestBilinearity(t *testing.T) {
|
|||
func TestG1Marshal(t *testing.T) {
|
||||
g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1))
|
||||
form := g.Marshal()
|
||||
_, ok := new(G1).Unmarshal(form)
|
||||
if !ok {
|
||||
_, err := new(G1).Unmarshal(form)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal")
|
||||
}
|
||||
|
||||
g.ScalarBaseMult(Order)
|
||||
form = g.Marshal()
|
||||
g2, ok := new(G1).Unmarshal(form)
|
||||
if !ok {
|
||||
|
||||
g2 := new(G1)
|
||||
if _, err = g2.Unmarshal(form); err != nil {
|
||||
t.Fatalf("failed to unmarshal ∞")
|
||||
}
|
||||
if !g2.p.IsInfinity() {
|
||||
|
|
@ -238,15 +239,15 @@ func TestG1Marshal(t *testing.T) {
|
|||
func TestG2Marshal(t *testing.T) {
|
||||
g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1))
|
||||
form := g.Marshal()
|
||||
_, ok := new(G2).Unmarshal(form)
|
||||
if !ok {
|
||||
_, err := new(G2).Unmarshal(form)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal")
|
||||
}
|
||||
|
||||
g.ScalarBaseMult(Order)
|
||||
form = g.Marshal()
|
||||
g2, ok := new(G2).Unmarshal(form)
|
||||
if !ok {
|
||||
g2 := new(G2)
|
||||
if _, err = g2.Unmarshal(form); err != nil {
|
||||
t.Fatalf("failed to unmarshal ∞")
|
||||
}
|
||||
if !g2.p.IsInfinity() {
|
||||
|
|
@ -273,12 +274,18 @@ func TestTripartiteDiffieHellman(t *testing.T) {
|
|||
b, _ := rand.Int(rand.Reader, Order)
|
||||
c, _ := rand.Int(rand.Reader, Order)
|
||||
|
||||
pa, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(a).Marshal())
|
||||
qa, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(a).Marshal())
|
||||
pb, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(b).Marshal())
|
||||
qb, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(b).Marshal())
|
||||
pc, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(c).Marshal())
|
||||
qc, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(c).Marshal())
|
||||
pa := new(G1)
|
||||
pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal())
|
||||
qa := new(G2)
|
||||
qa.Unmarshal(new(G2).ScalarBaseMult(a).Marshal())
|
||||
pb := new(G1)
|
||||
pb.Unmarshal(new(G1).ScalarBaseMult(b).Marshal())
|
||||
qb := new(G2)
|
||||
qb.Unmarshal(new(G2).ScalarBaseMult(b).Marshal())
|
||||
pc := new(G1)
|
||||
pc.Unmarshal(new(G1).ScalarBaseMult(c).Marshal())
|
||||
qc := new(G2)
|
||||
qc.Unmarshal(new(G2).ScalarBaseMult(c).Marshal())
|
||||
|
||||
k1 := Pair(pb, qc)
|
||||
k1.ScalarMult(k1, a)
|
||||
|
|
@ -76,7 +76,13 @@ func (c *twistPoint) IsOnCurve() bool {
|
|||
yy.Sub(yy, xxx)
|
||||
yy.Sub(yy, twistB)
|
||||
yy.Minimal()
|
||||
return yy.x.Sign() == 0 && yy.y.Sign() == 0
|
||||
|
||||
if yy.x.Sign() != 0 || yy.y.Sign() != 0 {
|
||||
return false
|
||||
}
|
||||
cneg := newTwistPoint(pool)
|
||||
cneg.Mul(c, Order, pool)
|
||||
return cneg.z.IsZero()
|
||||
}
|
||||
|
||||
func (c *twistPoint) SetInfinity() {
|
||||
|
|
@ -27,6 +27,7 @@ import (
|
|||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
|
|
@ -221,6 +222,9 @@ func New(mode SyncMode, stateDb ethdb.Database, mux *event.TypeMux, chain BlockC
|
|||
quitCh: make(chan struct{}),
|
||||
stateCh: make(chan dataPack),
|
||||
stateSyncStart: make(chan *stateSync),
|
||||
syncStatsState: stateSyncStats{
|
||||
processed: core.GetTrieSyncProgress(stateDb),
|
||||
},
|
||||
trackStateReq: make(chan *stateReq),
|
||||
}
|
||||
go dl.qosTuner()
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
|
|
@ -466,4 +467,7 @@ func (s *stateSync) updateStats(written, duplicate, unexpected int, duration tim
|
|||
if written > 0 || duplicate > 0 || unexpected > 0 {
|
||||
log.Info("Imported new state entries", "count", written, "elapsed", common.PrettyDuration(duration), "processed", s.d.syncStatsState.processed, "pending", s.d.syncStatsState.pending, "retry", len(s.tasks), "duplicate", s.d.syncStatsState.duplicate, "unexpected", s.d.syncStatsState.unexpected)
|
||||
}
|
||||
if written > 0 {
|
||||
core.WriteTrieSyncProgress(s.d.stateDB, s.d.syncStatsState.processed)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -633,7 +633,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) {
|
|||
}
|
||||
|
||||
// insert spawns a new goroutine to run a block insertion into the chain. If the
|
||||
// block's number is at the same height as the current import phase, if updates
|
||||
// block's number is at the same height as the current import phase, it updates
|
||||
// the phase states accordingly.
|
||||
func (f *Fetcher) insert(peer string, block *types.Block) {
|
||||
hash := block.Hash()
|
||||
|
|
|
|||
|
|
@ -140,10 +140,9 @@ func (h *HandlerT) GoTrace(file string, nsec uint) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// BlockProfile turns on CPU profiling for nsec seconds and writes
|
||||
// profile data to file. It uses a profile rate of 1 for most accurate
|
||||
// information. If a different rate is desired, set the rate
|
||||
// and write the profile manually.
|
||||
// BlockProfile turns on goroutine profiling for nsec seconds and writes profile data to
|
||||
// file. It uses a profile rate of 1 for most accurate information. If a different rate is
|
||||
// desired, set the rate and write the profile manually.
|
||||
func (*HandlerT) BlockProfile(file string, nsec uint) error {
|
||||
runtime.SetBlockProfileRate(1)
|
||||
time.Sleep(time.Duration(nsec) * time.Second)
|
||||
|
|
@ -162,6 +161,26 @@ func (*HandlerT) WriteBlockProfile(file string) error {
|
|||
return writeProfile("block", file)
|
||||
}
|
||||
|
||||
// MutexProfile turns on mutex profiling for nsec seconds and writes profile data to file.
|
||||
// It uses a profile rate of 1 for most accurate information. If a different rate is
|
||||
// desired, set the rate and write the profile manually.
|
||||
func (*HandlerT) MutexProfile(file string, nsec uint) error {
|
||||
runtime.SetMutexProfileFraction(1)
|
||||
time.Sleep(time.Duration(nsec) * time.Second)
|
||||
defer runtime.SetMutexProfileFraction(0)
|
||||
return writeProfile("mutex", file)
|
||||
}
|
||||
|
||||
// SetMutexProfileFraction sets the rate of mutex profiling.
|
||||
func (*HandlerT) SetMutexProfileFraction(rate int) {
|
||||
runtime.SetMutexProfileFraction(rate)
|
||||
}
|
||||
|
||||
// WriteMutexProfile writes a goroutine blocking profile to the given file.
|
||||
func (*HandlerT) WriteMutexProfile(file string) error {
|
||||
return writeProfile("mutex", file)
|
||||
}
|
||||
|
||||
// WriteMemProfile writes an allocation profile to the given file.
|
||||
// Note that the profiling rate cannot be set through the API,
|
||||
// it must be set on the command line.
|
||||
|
|
|
|||
|
|
@ -611,7 +611,7 @@ type CallArgs struct {
|
|||
Data hexutil.Bytes `json:"data"`
|
||||
}
|
||||
|
||||
func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, uint64, bool, error) {
|
||||
func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration) ([]byte, uint64, bool, error) {
|
||||
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
||||
|
||||
state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
||||
|
|
@ -630,7 +630,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
|
|||
// Set default gas & gas price if none were set
|
||||
gas, gasPrice := uint64(args.Gas), args.GasPrice.ToInt()
|
||||
if gas == 0 {
|
||||
gas = 50000000
|
||||
gas = math.MaxUint64 / 2
|
||||
}
|
||||
if gasPrice.Sign() == 0 {
|
||||
gasPrice = new(big.Int).SetUint64(defaultGasPrice)
|
||||
|
|
@ -642,14 +642,14 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
|
|||
// Setup context so it may be cancelled the call has completed
|
||||
// or, in case of unmetered gas, setup a context with a timeout.
|
||||
var cancel context.CancelFunc
|
||||
if vmCfg.DisableGasMetering {
|
||||
ctx, cancel = context.WithTimeout(ctx, time.Second*5)
|
||||
if timeout > 0 {
|
||||
ctx, cancel = context.WithTimeout(ctx, timeout)
|
||||
} else {
|
||||
ctx, cancel = context.WithCancel(ctx)
|
||||
}
|
||||
// Make sure the context is cancelled when the call has completed
|
||||
// this makes sure resources are cleaned up.
|
||||
defer func() { cancel() }()
|
||||
defer cancel()
|
||||
|
||||
// Get a new instance of the EVM.
|
||||
evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg)
|
||||
|
|
@ -676,7 +676,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
|
|||
// Call executes the given transaction on the state for the given block number.
|
||||
// It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
|
||||
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
|
||||
result, _, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true})
|
||||
result, _, _, err := s.doCall(ctx, args, blockNr, vm.Config{}, 5*time.Second)
|
||||
return (hexutil.Bytes)(result), err
|
||||
}
|
||||
|
||||
|
|
@ -705,7 +705,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h
|
|||
executable := func(gas uint64) bool {
|
||||
args.Gas = hexutil.Uint64(gas)
|
||||
|
||||
_, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{})
|
||||
_, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{}, 0)
|
||||
if err != nil || failed {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -307,6 +307,21 @@ web3._extend({
|
|||
call: 'debug_writeBlockProfile',
|
||||
params: 1
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'mutexProfile',
|
||||
call: 'debug_mutexProfile',
|
||||
params: 2
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'setMutexProfileRate',
|
||||
call: 'debug_setMutexProfileRate',
|
||||
params: 1
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'writeMutexProfile',
|
||||
call: 'debug_writeMutexProfile',
|
||||
params: 1
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'writeMemProfile',
|
||||
call: 'debug_writeMemProfile',
|
||||
|
|
|
|||
|
|
@ -144,7 +144,9 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num
|
|||
genesis := core.GetCanonicalHash(odr.Database(), 0)
|
||||
config, _ := core.GetChainConfig(odr.Database(), genesis)
|
||||
|
||||
core.SetReceiptsData(config, block, receipts)
|
||||
if err := core.SetReceiptsData(config, block, receipts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
core.WriteBlockReceipts(odr.Database(), hash, number, receipts)
|
||||
}
|
||||
return receipts, nil
|
||||
|
|
|
|||
|
|
@ -58,18 +58,18 @@ type trustedCheckpoint struct {
|
|||
var (
|
||||
mainnetCheckpoint = trustedCheckpoint{
|
||||
name: "mainnet",
|
||||
sectionIdx: 153,
|
||||
sectionHead: common.HexToHash("04c2114a8cbe49ba5c37a03cc4b4b8d3adfc0bd2c78e0e726405dd84afca1d63"),
|
||||
chtRoot: common.HexToHash("d7ec603e5d30b567a6e894ee7704e4603232f206d3e5a589794cec0c57bf318e"),
|
||||
bloomTrieRoot: common.HexToHash("0b139b8fb692e21f663ff200da287192201c28ef5813c1ac6ba02a0a4799eef9"),
|
||||
sectionIdx: 157,
|
||||
sectionHead: common.HexToHash("1963c080887ca7f406c2bb114293eea83e54f783f94df24b447f7e3b6317c747"),
|
||||
chtRoot: common.HexToHash("42abc436567dfb678a38fa6a9f881aa4c8a4cc8eaa2def08359292c3d0bd48ec"),
|
||||
bloomTrieRoot: common.HexToHash("281c9f8fb3cb8b37ae45e9907ef8f3b19cd22c54e297c2d6c09c1db1593dce42"),
|
||||
}
|
||||
|
||||
ropstenCheckpoint = trustedCheckpoint{
|
||||
name: "ropsten",
|
||||
sectionIdx: 79,
|
||||
sectionHead: common.HexToHash("1b1ba890510e06411fdee9bb64ca7705c56a1a4ce3559ddb34b3680c526cb419"),
|
||||
chtRoot: common.HexToHash("71d60207af74e5a22a3e1cfbfc89f9944f91b49aa980c86fba94d568369eaf44"),
|
||||
bloomTrieRoot: common.HexToHash("70aca4b3b6d08dde8704c95cedb1420394453c1aec390947751e69ff8c436360"),
|
||||
sectionIdx: 83,
|
||||
sectionHead: common.HexToHash("3ca623586bc0da35f1fc8d9b6b55950f3b1f69be9c6501846a2df672adb61236"),
|
||||
chtRoot: common.HexToHash("8f08ec7783969768c6ef06e5fe3398223cbf4ae2907b676da7b6fe6c7f55b059"),
|
||||
bloomTrieRoot: common.HexToHash("02d86d3c6a87f8f8a92c2a59bbba2132ff6f9f61b0915a5dc28a9d8279219fd0"),
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"log"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const FANOUT = 128
|
||||
|
|
@ -114,7 +115,7 @@ func Example() {
|
|||
|
||||
// Threadsafe registration
|
||||
t := GetOrRegisterTimer("db.get.latency", nil)
|
||||
t.Time(func() {})
|
||||
t.Time(func() { time.Sleep(10 * time.Millisecond) })
|
||||
t.Update(1)
|
||||
|
||||
fmt.Println(c.Count())
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ func TestTimerStop(t *testing.T) {
|
|||
func TestTimerFunc(t *testing.T) {
|
||||
tm := NewTimer()
|
||||
tm.Time(func() { time.Sleep(50e6) })
|
||||
if max := tm.Max(); 45e6 > max || max > 55e6 {
|
||||
t.Errorf("tm.Max(): 45e6 > %v || %v > 55e6\n", max, max)
|
||||
if max := tm.Max(); 35e6 > max || max > 95e6 {
|
||||
t.Errorf("tm.Max(): 35e6 > %v || %v > 95e6\n", max, max)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ var DefaultConfig = Config{
|
|||
DataDir: DefaultDataDir(),
|
||||
HTTPPort: DefaultHTTPPort,
|
||||
HTTPModules: []string{"net", "web3"},
|
||||
HTTPVirtualHosts: []string{"localhost"},
|
||||
WSPort: DefaultWSPort,
|
||||
WSModules: []string{"net", "web3"},
|
||||
P2P: p2p.Config{
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import (
|
|||
const (
|
||||
VersionMajor = 1 // Major version component of the current release
|
||||
VersionMinor = 8 // Minor version component of the current release
|
||||
VersionPatch = 2 // Patch version component of the current release
|
||||
VersionPatch = 3 // Patch version component of the current release
|
||||
VersionMeta = "unstable" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -363,7 +363,7 @@ func TestRandomData(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestRandomBrokenData(t *testing.T) {
|
||||
func XTestRandomBrokenData(t *testing.T) {
|
||||
sizes := []int{1, 60, 83, 179, 253, 1024, 4095, 4096, 4097, 8191, 8192, 8193, 12287, 12288, 12289, 123456, 2345678}
|
||||
tester := &chunkerTester{t: t}
|
||||
chunker := NewTreeChunker(NewChunkerParams())
|
||||
|
|
|
|||
|
|
@ -107,17 +107,16 @@ func (s *WMailServer) DeliverMail(peer *whisper.Peer, request *whisper.Envelope)
|
|||
return
|
||||
}
|
||||
|
||||
ok, lower, upper, topic := s.validateRequest(peer.ID(), request)
|
||||
ok, lower, upper, bloom := s.validateRequest(peer.ID(), request)
|
||||
if ok {
|
||||
s.processRequest(peer, lower, upper, topic)
|
||||
s.processRequest(peer, lower, upper, bloom)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, topic whisper.TopicType) []*whisper.Envelope {
|
||||
func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, bloom []byte) []*whisper.Envelope {
|
||||
ret := make([]*whisper.Envelope, 0)
|
||||
var err error
|
||||
var zero common.Hash
|
||||
var empty whisper.TopicType
|
||||
kl := NewDbKey(lower, zero)
|
||||
ku := NewDbKey(upper, zero)
|
||||
i := s.db.NewIterator(&util.Range{Start: kl.raw, Limit: ku.raw}, nil)
|
||||
|
|
@ -130,7 +129,7 @@ func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, to
|
|||
log.Error(fmt.Sprintf("RLP decoding failed: %s", err))
|
||||
}
|
||||
|
||||
if topic == empty || envelope.Topic == topic {
|
||||
if whisper.BloomFilterMatch(bloom, envelope.Bloom()) {
|
||||
if peer == nil {
|
||||
// used for test purposes
|
||||
ret = append(ret, &envelope)
|
||||
|
|
@ -152,22 +151,16 @@ func (s *WMailServer) processRequest(peer *whisper.Peer, lower, upper uint32, to
|
|||
return ret
|
||||
}
|
||||
|
||||
func (s *WMailServer) validateRequest(peerID []byte, request *whisper.Envelope) (bool, uint32, uint32, whisper.TopicType) {
|
||||
var topic whisper.TopicType
|
||||
func (s *WMailServer) validateRequest(peerID []byte, request *whisper.Envelope) (bool, uint32, uint32, []byte) {
|
||||
if s.pow > 0.0 && request.PoW() < s.pow {
|
||||
return false, 0, 0, topic
|
||||
return false, 0, 0, nil
|
||||
}
|
||||
|
||||
f := whisper.Filter{KeySym: s.key}
|
||||
decrypted := request.Open(&f)
|
||||
if decrypted == nil {
|
||||
log.Warn(fmt.Sprintf("Failed to decrypt p2p request"))
|
||||
return false, 0, 0, topic
|
||||
}
|
||||
|
||||
if len(decrypted.Payload) < 8 {
|
||||
log.Warn(fmt.Sprintf("Undersized p2p request"))
|
||||
return false, 0, 0, topic
|
||||
return false, 0, 0, nil
|
||||
}
|
||||
|
||||
src := crypto.FromECDSAPub(decrypted.Src)
|
||||
|
|
@ -179,15 +172,24 @@ func (s *WMailServer) validateRequest(peerID []byte, request *whisper.Envelope)
|
|||
// if !bytes.Equal(peerID, src) {
|
||||
if src == nil {
|
||||
log.Warn(fmt.Sprintf("Wrong signature of p2p request"))
|
||||
return false, 0, 0, topic
|
||||
return false, 0, 0, nil
|
||||
}
|
||||
|
||||
var bloom []byte
|
||||
payloadSize := len(decrypted.Payload)
|
||||
if payloadSize < 8 {
|
||||
log.Warn(fmt.Sprintf("Undersized p2p request"))
|
||||
return false, 0, 0, nil
|
||||
} else if payloadSize == 8 {
|
||||
bloom = whisper.MakeFullNodeBloom()
|
||||
} else if payloadSize < 8+whisper.BloomFilterSize {
|
||||
log.Warn(fmt.Sprintf("Undersized bloom filter in p2p request"))
|
||||
return false, 0, 0, nil
|
||||
} else {
|
||||
bloom = decrypted.Payload[8 : 8+whisper.BloomFilterSize]
|
||||
}
|
||||
|
||||
lower := binary.BigEndian.Uint32(decrypted.Payload[:4])
|
||||
upper := binary.BigEndian.Uint32(decrypted.Payload[4:8])
|
||||
|
||||
if len(decrypted.Payload) >= 8+whisper.TopicLength {
|
||||
topic = whisper.BytesToTopic(decrypted.Payload[8:])
|
||||
}
|
||||
|
||||
return true, lower, upper, topic
|
||||
return true, lower, upper, bloom
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package mailserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
|
|
@ -61,7 +62,7 @@ func generateEnvelope(t *testing.T) *whisper.Envelope {
|
|||
h := crypto.Keccak256Hash([]byte("test sample data"))
|
||||
params := &whisper.MessageParams{
|
||||
KeySym: h[:],
|
||||
Topic: whisper.TopicType{},
|
||||
Topic: whisper.TopicType{0x1F, 0x7E, 0xA1, 0x7F},
|
||||
Payload: []byte("test payload"),
|
||||
PoW: powRequirement,
|
||||
WorkTime: 2,
|
||||
|
|
@ -121,6 +122,7 @@ func deliverTest(t *testing.T, server *WMailServer, env *whisper.Envelope) {
|
|||
upp: birth + 1,
|
||||
key: testPeerID,
|
||||
}
|
||||
|
||||
singleRequest(t, server, env, p, true)
|
||||
|
||||
p.low, p.upp = birth+1, 0xffffffff
|
||||
|
|
@ -131,14 +133,14 @@ func deliverTest(t *testing.T, server *WMailServer, env *whisper.Envelope) {
|
|||
|
||||
p.low = birth - 1
|
||||
p.upp = birth + 1
|
||||
p.topic[0]++
|
||||
p.topic[0] = 0xFF
|
||||
singleRequest(t, server, env, p, false)
|
||||
}
|
||||
|
||||
func singleRequest(t *testing.T, server *WMailServer, env *whisper.Envelope, p *ServerTestParams, expect bool) {
|
||||
request := createRequest(t, p)
|
||||
src := crypto.FromECDSAPub(&p.key.PublicKey)
|
||||
ok, lower, upper, topic := server.validateRequest(src, request)
|
||||
ok, lower, upper, bloom := server.validateRequest(src, request)
|
||||
if !ok {
|
||||
t.Fatalf("request validation failed, seed: %d.", seed)
|
||||
}
|
||||
|
|
@ -148,12 +150,13 @@ func singleRequest(t *testing.T, server *WMailServer, env *whisper.Envelope, p *
|
|||
if upper != p.upp {
|
||||
t.Fatalf("request validation failed (upper bound), seed: %d.", seed)
|
||||
}
|
||||
if topic != p.topic {
|
||||
expectedBloom := whisper.TopicToBloom(p.topic)
|
||||
if !bytes.Equal(bloom, expectedBloom) {
|
||||
t.Fatalf("request validation failed (topic), seed: %d.", seed)
|
||||
}
|
||||
|
||||
var exist bool
|
||||
mail := server.processRequest(nil, p.low, p.upp, p.topic)
|
||||
mail := server.processRequest(nil, p.low, p.upp, bloom)
|
||||
for _, msg := range mail {
|
||||
if msg.Hash() == env.Hash() {
|
||||
exist = true
|
||||
|
|
@ -166,7 +169,7 @@ func singleRequest(t *testing.T, server *WMailServer, env *whisper.Envelope, p *
|
|||
}
|
||||
|
||||
src[0]++
|
||||
ok, lower, upper, topic = server.validateRequest(src, request)
|
||||
ok, lower, upper, bloom = server.validateRequest(src, request)
|
||||
if !ok {
|
||||
// request should be valid regardless of signature
|
||||
t.Fatalf("request validation false negative, seed: %d (lower: %d, upper: %d).", seed, lower, upper)
|
||||
|
|
@ -174,10 +177,11 @@ func singleRequest(t *testing.T, server *WMailServer, env *whisper.Envelope, p *
|
|||
}
|
||||
|
||||
func createRequest(t *testing.T, p *ServerTestParams) *whisper.Envelope {
|
||||
data := make([]byte, 8+whisper.TopicLength)
|
||||
bloom := whisper.TopicToBloom(p.topic)
|
||||
data := make([]byte, 8)
|
||||
binary.BigEndian.PutUint32(data, p.low)
|
||||
binary.BigEndian.PutUint32(data[4:], p.upp)
|
||||
copy(data[8:], p.topic[:])
|
||||
data = append(data, bloom...)
|
||||
|
||||
key, err := shh.GetSymKey(keyID)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ const (
|
|||
aesKeyLength = 32 // in bytes
|
||||
aesNonceLength = 12 // in bytes; for more info please see cipher.gcmStandardNonceSize & aesgcm.NonceSize()
|
||||
keyIDSize = 32 // in bytes
|
||||
bloomFilterSize = 64 // in bytes
|
||||
BloomFilterSize = 64 // in bytes
|
||||
flagsLength = 1
|
||||
|
||||
EnvelopeHeaderLength = 20
|
||||
|
|
|
|||
|
|
@ -208,6 +208,10 @@ func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
|
|||
|
||||
// Open tries to decrypt an envelope, and populates the message fields in case of success.
|
||||
func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) {
|
||||
if watcher == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The API interface forbids filters doing both symmetric and asymmetric encryption.
|
||||
if watcher.expectsAsymmetricEncryption() && watcher.expectsSymmetricEncryption() {
|
||||
return nil
|
||||
|
|
@ -249,7 +253,7 @@ func (e *Envelope) Bloom() []byte {
|
|||
|
||||
// TopicToBloom converts the topic (4 bytes) to the bloom filter (64 bytes)
|
||||
func TopicToBloom(topic TopicType) []byte {
|
||||
b := make([]byte, bloomFilterSize)
|
||||
b := make([]byte, BloomFilterSize)
|
||||
var index [3]int
|
||||
for j := 0; j < 3; j++ {
|
||||
index[j] = int(topic[j])
|
||||
|
|
@ -265,3 +269,11 @@ func TopicToBloom(topic TopicType) []byte {
|
|||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// GetEnvelope retrieves an envelope from the message queue by its hash.
|
||||
// It returns nil if the envelope can not be found.
|
||||
func (w *Whisper) GetEnvelope(hash common.Hash) *Envelope {
|
||||
w.poolMu.RLock()
|
||||
defer w.poolMu.RUnlock()
|
||||
return w.envelopes[hash]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,20 +191,6 @@ func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (f *Filter) processEnvelope(env *Envelope) *ReceivedMessage {
|
||||
if f.MatchEnvelope(env) {
|
||||
msg := env.Open(f)
|
||||
if msg != nil {
|
||||
return msg
|
||||
}
|
||||
|
||||
log.Trace("processing envelope: failed to open", "hash", env.Hash().Hex())
|
||||
} else {
|
||||
log.Trace("processing envelope: does not match", "hash", env.Hash().Hex())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Filter) expectsAsymmetricEncryption() bool {
|
||||
return f.KeyAsym != nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ func newPeer(host *Whisper, remote *p2p.Peer, rw p2p.MsgReadWriter) *Peer {
|
|||
powRequirement: 0.0,
|
||||
known: set.New(),
|
||||
quit: make(chan struct{}),
|
||||
bloomFilter: makeFullNodeBloom(),
|
||||
bloomFilter: MakeFullNodeBloom(),
|
||||
fullNode: true,
|
||||
}
|
||||
}
|
||||
|
|
@ -120,7 +120,7 @@ func (peer *Peer) handshake() error {
|
|||
err = s.Decode(&bloom)
|
||||
if err == nil {
|
||||
sz := len(bloom)
|
||||
if sz != bloomFilterSize && sz != 0 {
|
||||
if sz != BloomFilterSize && sz != 0 {
|
||||
return fmt.Errorf("peer [%x] sent bad status message: wrong bloom filter size %d", peer.ID(), sz)
|
||||
}
|
||||
peer.setBloomFilter(bloom)
|
||||
|
|
@ -229,7 +229,7 @@ func (peer *Peer) notifyAboutBloomFilterChange(bloom []byte) error {
|
|||
func (peer *Peer) bloomMatch(env *Envelope) bool {
|
||||
peer.bloomMu.Lock()
|
||||
defer peer.bloomMu.Unlock()
|
||||
return peer.fullNode || bloomFilterMatch(peer.bloomFilter, env.Bloom())
|
||||
return peer.fullNode || BloomFilterMatch(peer.bloomFilter, env.Bloom())
|
||||
}
|
||||
|
||||
func (peer *Peer) setBloomFilter(bloom []byte) {
|
||||
|
|
@ -238,13 +238,13 @@ func (peer *Peer) setBloomFilter(bloom []byte) {
|
|||
peer.bloomFilter = bloom
|
||||
peer.fullNode = isFullNode(bloom)
|
||||
if peer.fullNode && peer.bloomFilter == nil {
|
||||
peer.bloomFilter = makeFullNodeBloom()
|
||||
peer.bloomFilter = MakeFullNodeBloom()
|
||||
}
|
||||
}
|
||||
|
||||
func makeFullNodeBloom() []byte {
|
||||
bloom := make([]byte, bloomFilterSize)
|
||||
for i := 0; i < bloomFilterSize; i++ {
|
||||
func MakeFullNodeBloom() []byte {
|
||||
bloom := make([]byte, BloomFilterSize)
|
||||
for i := 0; i < BloomFilterSize; i++ {
|
||||
bloom[i] = 0xFF
|
||||
}
|
||||
return bloom
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ func resetParams(t *testing.T) {
|
|||
}
|
||||
|
||||
func initBloom(t *testing.T) {
|
||||
masterBloomFilter = make([]byte, bloomFilterSize)
|
||||
masterBloomFilter = make([]byte, BloomFilterSize)
|
||||
_, err := mrand.Read(masterBloomFilter)
|
||||
if err != nil {
|
||||
t.Fatalf("rand failed: %s.", err)
|
||||
|
|
@ -164,7 +164,7 @@ func initBloom(t *testing.T) {
|
|||
masterBloomFilter[i] = 0xFF
|
||||
}
|
||||
|
||||
if !bloomFilterMatch(masterBloomFilter, msgBloom) {
|
||||
if !BloomFilterMatch(masterBloomFilter, msgBloom) {
|
||||
t.Fatalf("bloom mismatch on initBloom.")
|
||||
}
|
||||
}
|
||||
|
|
@ -178,7 +178,7 @@ func initialize(t *testing.T) {
|
|||
|
||||
for i := 0; i < NumNodes; i++ {
|
||||
var node TestNode
|
||||
b := make([]byte, bloomFilterSize)
|
||||
b := make([]byte, BloomFilterSize)
|
||||
copy(b, masterBloomFilter)
|
||||
node.shh = New(&DefaultConfig)
|
||||
node.shh.SetMinimumPoW(masterPow)
|
||||
|
|
|
|||
|
|
@ -232,11 +232,11 @@ func (whisper *Whisper) SetMaxMessageSize(size uint32) error {
|
|||
|
||||
// SetBloomFilter sets the new bloom filter
|
||||
func (whisper *Whisper) SetBloomFilter(bloom []byte) error {
|
||||
if len(bloom) != bloomFilterSize {
|
||||
if len(bloom) != BloomFilterSize {
|
||||
return fmt.Errorf("invalid bloom filter size: %d", len(bloom))
|
||||
}
|
||||
|
||||
b := make([]byte, bloomFilterSize)
|
||||
b := make([]byte, BloomFilterSize)
|
||||
copy(b, bloom)
|
||||
|
||||
whisper.settings.Store(bloomFilterIdx, b)
|
||||
|
|
@ -558,14 +558,14 @@ func (whisper *Whisper) Subscribe(f *Filter) (string, error) {
|
|||
// updateBloomFilter recalculates the new value of bloom filter,
|
||||
// and informs the peers if necessary.
|
||||
func (whisper *Whisper) updateBloomFilter(f *Filter) {
|
||||
aggregate := make([]byte, bloomFilterSize)
|
||||
aggregate := make([]byte, BloomFilterSize)
|
||||
for _, t := range f.Topics {
|
||||
top := BytesToTopic(t)
|
||||
b := TopicToBloom(top)
|
||||
aggregate = addBloom(aggregate, b)
|
||||
}
|
||||
|
||||
if !bloomFilterMatch(whisper.BloomFilter(), aggregate) {
|
||||
if !BloomFilterMatch(whisper.BloomFilter(), aggregate) {
|
||||
// existing bloom filter must be updated
|
||||
aggregate = addBloom(whisper.BloomFilter(), aggregate)
|
||||
whisper.SetBloomFilter(aggregate)
|
||||
|
|
@ -701,7 +701,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
|||
case bloomFilterExCode:
|
||||
var bloom []byte
|
||||
err := packet.Decode(&bloom)
|
||||
if err == nil && len(bloom) != bloomFilterSize {
|
||||
if err == nil && len(bloom) != BloomFilterSize {
|
||||
err = fmt.Errorf("wrong bloom filter size %d", len(bloom))
|
||||
}
|
||||
|
||||
|
|
@ -779,11 +779,11 @@ func (whisper *Whisper) add(envelope *Envelope, isP2P bool) (bool, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if !bloomFilterMatch(whisper.BloomFilter(), envelope.Bloom()) {
|
||||
if !BloomFilterMatch(whisper.BloomFilter(), envelope.Bloom()) {
|
||||
// maybe the value was recently changed, and the peers did not adjust yet.
|
||||
// in this case the previous value is retrieved by BloomFilterTolerance()
|
||||
// for a short period of peer synchronization.
|
||||
if !bloomFilterMatch(whisper.BloomFilterTolerance(), envelope.Bloom()) {
|
||||
if !BloomFilterMatch(whisper.BloomFilterTolerance(), envelope.Bloom()) {
|
||||
return false, fmt.Errorf("envelope does not match bloom filter, hash=[%v], bloom: \n%x \n%x \n%x",
|
||||
envelope.Hash().Hex(), whisper.BloomFilter(), envelope.Bloom(), envelope.Topic)
|
||||
}
|
||||
|
|
@ -1025,12 +1025,12 @@ func isFullNode(bloom []byte) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func bloomFilterMatch(filter, sample []byte) bool {
|
||||
func BloomFilterMatch(filter, sample []byte) bool {
|
||||
if filter == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
for i := 0; i < bloomFilterSize; i++ {
|
||||
for i := 0; i < BloomFilterSize; i++ {
|
||||
f := filter[i]
|
||||
s := sample[i]
|
||||
if (f | s) != f {
|
||||
|
|
@ -1042,8 +1042,8 @@ func bloomFilterMatch(filter, sample []byte) bool {
|
|||
}
|
||||
|
||||
func addBloom(a, b []byte) []byte {
|
||||
c := make([]byte, bloomFilterSize)
|
||||
for i := 0; i < bloomFilterSize; i++ {
|
||||
c := make([]byte, BloomFilterSize)
|
||||
for i := 0; i < BloomFilterSize; i++ {
|
||||
c[i] = a[i] | b[i]
|
||||
}
|
||||
return c
|
||||
|
|
|
|||
|
|
@ -826,11 +826,11 @@ func TestSymmetricSendKeyMismatch(t *testing.T) {
|
|||
func TestBloom(t *testing.T) {
|
||||
topic := TopicType{0, 0, 255, 6}
|
||||
b := TopicToBloom(topic)
|
||||
x := make([]byte, bloomFilterSize)
|
||||
x := make([]byte, BloomFilterSize)
|
||||
x[0] = byte(1)
|
||||
x[32] = byte(1)
|
||||
x[bloomFilterSize-1] = byte(128)
|
||||
if !bloomFilterMatch(x, b) || !bloomFilterMatch(b, x) {
|
||||
x[BloomFilterSize-1] = byte(128)
|
||||
if !BloomFilterMatch(x, b) || !BloomFilterMatch(b, x) {
|
||||
t.Fatalf("bloom filter does not match the mask")
|
||||
}
|
||||
|
||||
|
|
@ -842,11 +842,11 @@ func TestBloom(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("math rand error")
|
||||
}
|
||||
if !bloomFilterMatch(b, b) {
|
||||
if !BloomFilterMatch(b, b) {
|
||||
t.Fatalf("bloom filter does not match self")
|
||||
}
|
||||
x = addBloom(x, b)
|
||||
if !bloomFilterMatch(x, b) {
|
||||
if !BloomFilterMatch(x, b) {
|
||||
t.Fatalf("bloom filter does not match combined bloom")
|
||||
}
|
||||
if !isFullNode(nil) {
|
||||
|
|
@ -856,16 +856,16 @@ func TestBloom(t *testing.T) {
|
|||
if isFullNode(x) {
|
||||
t.Fatalf("isFullNode false positive")
|
||||
}
|
||||
for i := 0; i < bloomFilterSize; i++ {
|
||||
for i := 0; i < BloomFilterSize; i++ {
|
||||
b[i] = byte(255)
|
||||
}
|
||||
if !isFullNode(b) {
|
||||
t.Fatalf("isFullNode false negative")
|
||||
}
|
||||
if bloomFilterMatch(x, b) {
|
||||
if BloomFilterMatch(x, b) {
|
||||
t.Fatalf("bloomFilterMatch false positive")
|
||||
}
|
||||
if !bloomFilterMatch(b, x) {
|
||||
if !BloomFilterMatch(b, x) {
|
||||
t.Fatalf("bloomFilterMatch false negative")
|
||||
}
|
||||
|
||||
|
|
@ -879,7 +879,7 @@ func TestBloom(t *testing.T) {
|
|||
t.Fatalf("failed to set bloom filter: %s", err)
|
||||
}
|
||||
f = w.BloomFilter()
|
||||
if !bloomFilterMatch(f, x) || !bloomFilterMatch(x, f) {
|
||||
if !BloomFilterMatch(f, x) || !BloomFilterMatch(x, f) {
|
||||
t.Fatalf("retireved wrong bloom filter")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue