Merge branch 'master' of https://github.com/v2fly/v2ray-core into v2fly-master

pull/2764/head
Kslr 2020-10-11 00:45:44 +08:00
commit 98911dc9f3
No known key found for this signature in database
GPG Key ID: 0AF5F66FA1E887CE
345 changed files with 1585 additions and 37219 deletions

View File

@ -1,42 +1,23 @@
run:
timeout: 5m
skip-dirs:
- external
skip-files:
- generated.*
issues:
new: true
exclude-rules:
- path: _test\.go
linters:
- gocyclo
- errcheck
- dupl
- gosec
- goconst
linters:
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
- errcheck
- exhaustive
- goconst
- gocritic
- gocyclo
- gofmt
- goimports
- golint
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- interfacer
- misspell
- nakedret
- noctx
@ -49,6 +30,9 @@ linters:
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
disable:
- deadcode
- errcheck
- unused

View File

@ -15,6 +15,7 @@ on:
jobs:
analyze:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ubuntu-latest
strategy:
fail-fast: false

View File

@ -8,6 +8,7 @@ on:
jobs:
coverage:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x

View File

@ -13,6 +13,7 @@ on:
jobs:
lint:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x

View File

@ -6,6 +6,7 @@ on:
jobs:
sign:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ubuntu-latest
steps:
- name: Checkout default branch

View File

@ -14,4 +14,4 @@ jobs:
stale-issue-message: "This issue is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days"
stale-pr-message: 'It has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days'
days-before-stale: 120
days-before-close: 5
days-before-close: 5

View File

@ -17,6 +17,7 @@ on:
jobs:
test:
if: github.repository != 'v2ray/v2ray-core'
runs-on: ${{ matrix.os }}
strategy:
matrix:

View File

@ -6,6 +6,7 @@ on:
jobs:
update:
if: github.repository == 'v2fly/v2ray-core'
runs-on: ubuntu-latest
steps:
- name: Checkout codebase

View File

@ -2,10 +2,12 @@
# STEP 1 build executable binary
############################
FROM golang:alpine AS builder
RUN apk update && apk add --no-cache git bash wget curl
WORKDIR /go/src/v2ray.com/core
WORKDIR /build
RUN git clone --progress https://github.com/v2fly/v2ray-core.git . && \
bash ./release/user-package.sh nosource noconf codename=$(git describe --tags) buildname=docker-fly abpathtgz=/tmp/v2ray.tgz
bash ./release/user-package.sh nosource noconf codename=$(git describe --abbrev=0 --tags) buildname=docker-fly abpathtgz=/tmp/v2ray.tgz
############################
# STEP 2 build a small image
############################
@ -20,4 +22,3 @@ RUN apk update && apk add ca-certificates && \
#ENTRYPOINT ["/usr/bin/v2ray/v2ray"]
ENV PATH /usr/bin/v2ray:$PATH
CMD ["v2ray", "-config=/etc/v2ray/config.json"]

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015-2020 V2Ray
Copyright (c) 2015-2020 V2Fly Community
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -3,19 +3,21 @@
***
# Project V
![](https://github.com/v2fly/v2ray-core/workflows/Test/badge.svg)
[![codecov.io][3]][4] [![GoDoc][5]][6] [![codebeat][7]][8] [![Downloads][9]][10] [![Downloads][11]][12]
[3]: https://codecov.io/gh/v2fly/v2ray-core/branch/master/graph/badge.svg?branch=master "Coverage badge"
[![GitHub Test Badge][1]][2] [![codecov.io][3]][4] [![GoDoc][5]][6] [![codebeat][7]][8] [![Downloads][9]][10] [![Downloads][11]][12]
[1]: https://github.com/v2fly/v2ray-core/workflows/Test/badge.svg "GitHub Test Badge"
[2]: https://github.com/v2fly/v2ray-core/actions "GitHub Actions Page"
[3]: https://codecov.io/gh/v2fly/v2ray-core/branch/master/graph/badge.svg?branch=master "Coverage Badge"
[4]: https://codecov.io/gh/v2fly/v2ray-core?branch=master "Codecov Status"
[5]: https://godoc.org/v2ray.com/core?status.svg "GoDoc badge"
[5]: https://godoc.org/v2ray.com/core?status.svg "GoDoc Badge"
[6]: https://godoc.org/v2ray.com/core "GoDoc"
[7]: https://codebeat.co/badges/f2354ca8-3e24-463d-a2e3-159af73b2477 "Codebeat badge"
[8]: https://codebeat.co/projects/github-com-v2ray-v2ray-core-master "Codebeat"
[9]: https://img.shields.io/github/downloads/v2ray/v2ray-core/total.svg "All releases badge"
[10]: https://github.com/v2ray/v2ray-core/releases/ "All releases number"
[11]: https://img.shields.io/github/downloads/v2fly/v2ray-core/total.svg "All releases badge"
[12]: https://github.com/v2fly/v2ray-core/releases/ "All releases number"
[7]: https://goreportcard.com/badge/github.com/v2fly/v2ray-core "Goreportcard Badge"
[8]: https://goreportcard.com/report/github.com/v2fly/v2ray-core "Goreportcard Result"
[9]: https://img.shields.io/github/downloads/v2ray/v2ray-core/total.svg "v2ray/v2ray-core downloads count"
[10]: https://github.com/v2ray/v2ray-core/releases "v2ray/v2ray-core release page"
[11]: https://img.shields.io/github/downloads/v2fly/v2ray-core/total.svg "v2fly/v2ray-core downloads count"
[12]: https://github.com/v2fly/v2ray-core/releases "v2fly/v2ray-core release page"
Project V is a set of network tools that help you to build your own computer network. It secures your network connections and thus protects your privacy. See [our website](https://www.v2fly.org/) for more information.
@ -27,9 +29,9 @@ Project V is a set of network tools that help you to build your own computer net
This repo relies on the following third-party projects:
* In production:
* [gorilla/websocket](https://github.com/gorilla/websocket)
* [gRPC](https://google.golang.org/grpc)
* For testing only:
* [miekg/dns](https://github.com/miekg/dns)
* [h12w/socks](https://github.com/h12w/socks)
- In production:
- [gorilla/websocket](https://github.com/gorilla/websocket)
- [gRPC](https://google.golang.org/grpc)
- For testing only:
- [miekg/dns](https://github.com/miekg/dns)
- [h12w/socks](https://github.com/h12w/socks)

View File

@ -2,7 +2,7 @@
package commander
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"

View File

@ -34,7 +34,8 @@ type Config struct {
// Tag of the outbound handler that handles grpc connections.
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
// Services that supported by this server. All services must implement Service interface.
// Services that supported by this server. All services must implement Service
// interface.
Service []*serial.TypedMessage `protobuf:"bytes,2,rep,name=service,proto3" json:"service,omitempty"`
}

View File

@ -12,6 +12,7 @@ import "common/serial/typed_message.proto";
message Config {
// Tag of the outbound handler that handles grpc connections.
string tag = 1;
// Services that supported by this server. All services must implement Service interface.
// Services that supported by this server. All services must implement Service
// interface.
repeated v2ray.core.common.serial.TypedMessage service = 2;
}

View File

@ -8,7 +8,6 @@ option java_multiple_files = true;
message SessionConfig {
reserved 1;
}
message Config {

View File

@ -2,7 +2,7 @@
package dispatcher
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"

View File

@ -2,4 +2,4 @@
package dispatcher
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen

View File

@ -155,8 +155,9 @@ type Config struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Nameservers used by this DNS. Only traditional UDP servers are support at the moment.
// A special value 'localhost' as a domain address can be set to use DNS on local system.
// Nameservers used by this DNS. Only traditional UDP servers are support at
// the moment. A special value 'localhost' as a domain address can be set to
// use DNS on local system.
//
// Deprecated: Do not use.
NameServers []*net.Endpoint `protobuf:"bytes,1,rep,name=NameServers,proto3" json:"NameServers,omitempty"`
@ -167,7 +168,8 @@ type Config struct {
//
// Deprecated: Do not use.
Hosts map[string]*net.IPOrDomain `protobuf:"bytes,2,rep,name=Hosts,proto3" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes (IPv6).
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
// (IPv6).
ClientIp []byte `protobuf:"bytes,3,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
StaticHosts []*Config_HostMapping `protobuf:"bytes,4,rep,name=static_hosts,json=staticHosts,proto3" json:"static_hosts,omitempty"`
// Tag is the inbound tag of DNS client.
@ -368,8 +370,9 @@ type Config_HostMapping struct {
Type DomainMatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=v2ray.core.app.dns.DomainMatchingType" json:"type,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
Ip [][]byte `protobuf:"bytes,3,rep,name=ip,proto3" json:"ip,omitempty"`
// ProxiedDomain indicates the mapped domain has the same IP address on this domain. V2Ray will use this domain for IP queries.
// This field is only effective if ip is empty.
// ProxiedDomain indicates the mapped domain has the same IP address on this
// domain. V2Ray will use this domain for IP queries. This field is only
// effective if ip is empty.
ProxiedDomain string `protobuf:"bytes,4,opt,name=proxied_domain,json=proxiedDomain,proto3" json:"proxied_domain,omitempty"`
}

View File

@ -36,8 +36,9 @@ enum DomainMatchingType {
}
message Config {
// Nameservers used by this DNS. Only traditional UDP servers are support at the moment.
// A special value 'localhost' as a domain address can be set to use DNS on local system.
// Nameservers used by this DNS. Only traditional UDP servers are support at
// the moment. A special value 'localhost' as a domain address can be set to
// use DNS on local system.
repeated v2ray.core.common.net.Endpoint NameServers = 1 [deprecated = true];
// NameServer list used by this DNS client.
@ -47,7 +48,8 @@ message Config {
// Deprecated. Use static_hosts.
map<string, v2ray.core.common.net.IPOrDomain> Hosts = 2 [deprecated = true];
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes (IPv6).
// Client IP for EDNS client subnet. Must be 4 bytes (IPv4) or 16 bytes
// (IPv6).
bytes client_ip = 3;
message HostMapping {
@ -56,8 +58,9 @@ message Config {
repeated bytes ip = 3;
// ProxiedDomain indicates the mapped domain has the same IP address on this domain. V2Ray will use this domain for IP queries.
// This field is only effective if ip is empty.
// ProxiedDomain indicates the mapped domain has the same IP address on this
// domain. V2Ray will use this domain for IP queries. This field is only
// effective if ip is empty.
string proxied_domain = 4;
}

View File

@ -1,4 +1,4 @@
// Package dns is an implementation of core.DNS feature.
package dns
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen

View File

@ -14,8 +14,6 @@ import (
"sync/atomic"
"time"
dns_feature "v2ray.com/core/features/dns"
"golang.org/x/net/dns/dnsmessage"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
@ -23,6 +21,7 @@ import (
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal/pubsub"
"v2ray.com/core/common/task"
dns_feature "v2ray.com/core/features/dns"
"v2ray.com/core/features/routing"
"v2ray.com/core/transport/internet"
)
@ -221,13 +220,11 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPO
if d, ok := ctx.Deadline(); ok {
deadline = d
} else {
deadline = time.Now().Add(time.Second * 8)
deadline = time.Now().Add(time.Second * 5)
}
for _, req := range reqs {
go func(r *dnsRequest) {
// generate new context for each req, using same context
// may cause reqs all aborted if any one encounter an error
dnsCtx := context.Background()
@ -245,7 +242,8 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPO
// forced to use mux for DOH
dnsCtx = session.ContextWithMuxPrefered(dnsCtx, true)
dnsCtx, cancel := context.WithDeadline(dnsCtx, deadline)
var cancel context.CancelFunc
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
defer cancel()
b, err := dns.PackMessage(r.msg)
@ -269,7 +267,6 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPO
}
func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte, error) {
body := bytes.NewBuffer(b)
req, err := http.NewRequest("POST", s.dohURL, body)
if err != nil {

View File

@ -2,7 +2,7 @@
package dns
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
@ -209,7 +209,7 @@ func New(ctx context.Context, config *Config) (*Server, error) {
ruleIter = 0
ruleCurr++
}
} else { // No original rule, generate one according to current domain matcher (majorly for compability with tests)
} else { // No original rule, generate one according to current domain matcher (majorly for compatibility with tests)
info.domainRuleIdx = uint16(len(rules))
rules = append(rules, matcher.String())
}

View File

@ -2,7 +2,7 @@
package command
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"

View File

@ -6,12 +6,11 @@ option go_package = "v2ray.com/core/app/log/command";
option java_package = "com.v2ray.core.app.log.command";
option java_multiple_files = true;
message Config {
}
message Config {}
message RestartLoggerRequest {}
message RestartLoggerResponse{}
message RestartLoggerResponse {}
service LoggerService {
rpc RestartLogger(RestartLoggerRequest) returns (RestartLoggerResponse) {}

View File

@ -11,7 +11,7 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
const _ = grpc.SupportPackageIsVersion7
// LoggerServiceClient is the client API for LoggerService service.
//
@ -49,10 +49,17 @@ type LoggerServiceServer interface {
type UnimplementedLoggerServiceServer struct {
}
func (*UnimplementedLoggerServiceServer) RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error) {
func (UnimplementedLoggerServiceServer) RestartLogger(context.Context, *RestartLoggerRequest) (*RestartLoggerResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RestartLogger not implemented")
}
func (*UnimplementedLoggerServiceServer) mustEmbedUnimplementedLoggerServiceServer() {}
func (UnimplementedLoggerServiceServer) mustEmbedUnimplementedLoggerServiceServer() {}
// UnsafeLoggerServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to LoggerServiceServer will
// result in compilation errors.
type UnsafeLoggerServiceServer interface {
mustEmbedUnimplementedLoggerServiceServer()
}
func RegisterLoggerServiceServer(s *grpc.Server, srv LoggerServiceServer) {
s.RegisterService(&_LoggerService_serviceDesc, srv)

View File

@ -2,7 +2,7 @@
package log
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"

View File

@ -1,4 +1,4 @@
// Package policy is an implementation of policy.Manager feature.
package policy
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen

View File

@ -22,9 +22,7 @@ message AddInboundRequest {
core.InboundHandlerConfig inbound = 1;
}
message AddInboundResponse{
}
message AddInboundResponse {}
message RemoveInboundRequest {
string tag = 1;
@ -37,31 +35,26 @@ message AlterInboundRequest {
v2ray.core.common.serial.TypedMessage operation = 2;
}
message AlterInboundResponse {
}
message AlterInboundResponse {}
message AddOutboundRequest {
core.OutboundHandlerConfig outbound = 1;
}
message AddOutboundResponse {
}
message AddOutboundResponse {}
message RemoveOutboundRequest {
string tag = 1;
}
message RemoveOutboundResponse {
}
message RemoveOutboundResponse {}
message AlterOutboundRequest {
string tag = 1;
v2ray.core.common.serial.TypedMessage operation = 2;
}
message AlterOutboundResponse {
}
message AlterOutboundResponse {}
service HandlerService {
rpc AddInbound(AddInboundRequest) returns (AddInboundResponse) {}

View File

@ -11,7 +11,7 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
const _ = grpc.SupportPackageIsVersion7
// HandlerServiceClient is the client API for HandlerService service.
//
@ -104,25 +104,32 @@ type HandlerServiceServer interface {
type UnimplementedHandlerServiceServer struct {
}
func (*UnimplementedHandlerServiceServer) AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error) {
func (UnimplementedHandlerServiceServer) AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddInbound not implemented")
}
func (*UnimplementedHandlerServiceServer) RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error) {
func (UnimplementedHandlerServiceServer) RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RemoveInbound not implemented")
}
func (*UnimplementedHandlerServiceServer) AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error) {
func (UnimplementedHandlerServiceServer) AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AlterInbound not implemented")
}
func (*UnimplementedHandlerServiceServer) AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error) {
func (UnimplementedHandlerServiceServer) AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddOutbound not implemented")
}
func (*UnimplementedHandlerServiceServer) RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error) {
func (UnimplementedHandlerServiceServer) RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RemoveOutbound not implemented")
}
func (*UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error) {
func (UnimplementedHandlerServiceServer) AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AlterOutbound not implemented")
}
func (*UnimplementedHandlerServiceServer) mustEmbedUnimplementedHandlerServiceServer() {}
func (UnimplementedHandlerServiceServer) mustEmbedUnimplementedHandlerServiceServer() {}
// UnsafeHandlerServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to HandlerServiceServer will
// result in compilation errors.
type UnsafeHandlerServiceServer interface {
mustEmbedUnimplementedHandlerServiceServer()
}
func RegisterHandlerServiceServer(s *grpc.Server, srv HandlerServiceServer) {
s.RegisterService(&_HandlerService_serviceDesc, srv)

View File

@ -1,3 +1,3 @@
package command
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen

View File

@ -11,8 +11,7 @@ import "common/net/port.proto";
import "transport/internet/config.proto";
import "common/serial/typed_message.proto";
message InboundConfig {
}
message InboundConfig {}
message AllocationStrategy {
enum Type {
@ -36,7 +35,6 @@ message AllocationStrategy {
// Default value is 3 if unset.
AllocationStrategyConcurrency concurrency = 2;
message AllocationStrategyRefresh {
uint32 value = 1;
}
@ -81,9 +79,7 @@ message InboundHandlerConfig {
v2ray.core.common.serial.TypedMessage proxy_settings = 3;
}
message OutboundConfig {
}
message OutboundConfig {}
message SenderConfig {
// Send traffic through the given IP. Only IP is allowed.

View File

@ -1,6 +1,6 @@
package inbound
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"

View File

@ -1,6 +1,6 @@
package outbound
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"

View File

@ -19,7 +19,6 @@ message Control {
message BridgeConfig {
string tag = 1;
string domain = 2;
}
message PortalConfig {

View File

@ -2,7 +2,7 @@
package reverse
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"

View File

@ -2,10 +2,11 @@
package command
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
"time"
"google.golang.org/grpc"
@ -38,7 +39,8 @@ func (s *routingServer) TestRoute(ctx context.Context, request *TestRouteRequest
return nil, err
}
if request.PublishResult && s.routingStats != nil {
s.routingStats.Publish(route)
ctx, _ := context.WithTimeout(context.Background(), 4*time.Second) // nolint: govet
s.routingStats.Publish(ctx, route)
}
return AsProtobufMessage(request.FieldSelectors)(route), nil
}
@ -55,10 +57,13 @@ func (s *routingServer) SubscribeRoutingStats(request *SubscribeRoutingStatsRequ
defer stats.UnsubscribeClosableChannel(s.routingStats, subscriber) // nolint: errcheck
for {
select {
case value, received := <-subscriber:
case value, ok := <-subscriber:
if !ok {
return newError("Upstream closed the subscriber channel.")
}
route, ok := value.(routing.Route)
if !(received && ok) {
return newError("Receiving upstream statistics failed.")
if !ok {
return newError("Upstream sent malformed statistics.")
}
err := stream.Send(genMessage(route))
if err != nil {

View File

@ -27,7 +27,8 @@ const (
const _ = proto.ProtoPackageIsVersion4
// RoutingContext is the context with information relative to routing process.
// It conforms to the structure of v2ray.core.features.routing.Context and v2ray.core.features.routing.Route.
// It conforms to the structure of v2ray.core.features.routing.Context and
// v2ray.core.features.routing.Route.
type RoutingContext struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -163,17 +164,22 @@ func (x *RoutingContext) GetOutboundTag() string {
return ""
}
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if opened by v2ray-core.
// * FieldSelectors selects a subset of fields in routing statistics to return. Valid selectors:
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
// opened by v2ray-core.
// * FieldSelectors selects a subset of fields in routing statistics to return.
// Valid selectors:
// - inbound: Selects connection's inbound tag.
// - network: Selects connection's network.
// - ip: Equivalent as "ip_source" and "ip_target", selects both source and target IP.
// - port: Equivalent as "port_source" and "port_target", selects both source and target port.
// - ip: Equivalent as "ip_source" and "ip_target", selects both source and
// target IP.
// - port: Equivalent as "port_source" and "port_target", selects both source
// and target port.
// - domain: Selects target domain.
// - protocol: Select connection's protocol.
// - user: Select connection's inbound user email.
// - attributes: Select connection's additional attributes.
// - outbound: Equivalent as "outbound" and "outbound_group", select both outbound tag and outbound group tags.
// - outbound: Equivalent as "outbound" and "outbound_group", select both
// outbound tag and outbound group tags.
// * If FieldSelectors is left empty, all fields will be returned.
type SubscribeRoutingStatsRequest struct {
state protoimpl.MessageState
@ -222,10 +228,13 @@ func (x *SubscribeRoutingStatsRequest) GetFieldSelectors() []string {
return nil
}
// TestRouteRequest manually tests a routing result according to the routing context message.
// TestRouteRequest manually tests a routing result according to the routing
// context message.
// * RoutingContext is the routing message without outbound information.
// * FieldSelectors selects the fields to return in the routing result. All fields are returned if left empty.
// * PublishResult broadcasts the routing result to routing statistics channel if set true.
// * FieldSelectors selects the fields to return in the routing result. All
// fields are returned if left empty.
// * PublishResult broadcasts the routing result to routing statistics channel
// if set true.
type TestRouteRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache

View File

@ -9,7 +9,8 @@ option java_multiple_files = true;
import "common/net/network.proto";
// RoutingContext is the context with information relative to routing process.
// It conforms to the structure of v2ray.core.features.routing.Context and v2ray.core.features.routing.Route.
// It conforms to the structure of v2ray.core.features.routing.Context and
// v2ray.core.features.routing.Route.
message RoutingContext {
string InboundTag = 1;
v2ray.core.common.net.Network Network = 2;
@ -25,26 +26,34 @@ message RoutingContext {
string OutboundTag = 12;
}
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if opened by v2ray-core.
// * FieldSelectors selects a subset of fields in routing statistics to return. Valid selectors:
// SubscribeRoutingStatsRequest subscribes to routing statistics channel if
// opened by v2ray-core.
// * FieldSelectors selects a subset of fields in routing statistics to return.
// Valid selectors:
// - inbound: Selects connection's inbound tag.
// - network: Selects connection's network.
// - ip: Equivalent as "ip_source" and "ip_target", selects both source and target IP.
// - port: Equivalent as "port_source" and "port_target", selects both source and target port.
// - ip: Equivalent as "ip_source" and "ip_target", selects both source and
// target IP.
// - port: Equivalent as "port_source" and "port_target", selects both source
// and target port.
// - domain: Selects target domain.
// - protocol: Select connection's protocol.
// - user: Select connection's inbound user email.
// - attributes: Select connection's additional attributes.
// - outbound: Equivalent as "outbound" and "outbound_group", select both outbound tag and outbound group tags.
// - outbound: Equivalent as "outbound" and "outbound_group", select both
// outbound tag and outbound group tags.
// * If FieldSelectors is left empty, all fields will be returned.
message SubscribeRoutingStatsRequest {
repeated string FieldSelectors = 1;
}
// TestRouteRequest manually tests a routing result according to the routing context message.
// TestRouteRequest manually tests a routing result according to the routing
// context message.
// * RoutingContext is the routing message without outbound information.
// * FieldSelectors selects the fields to return in the routing result. All fields are returned if left empty.
// * PublishResult broadcasts the routing result to routing statistics channel if set true.
// * FieldSelectors selects the fields to return in the routing result. All
// fields are returned if left empty.
// * PublishResult broadcasts the routing result to routing statistics channel
// if set true.
message TestRouteRequest {
RoutingContext RoutingContext = 1;
repeated string FieldSelectors = 2;
@ -52,7 +61,8 @@ message TestRouteRequest {
}
service RoutingService {
rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest) returns (stream RoutingContext) {}
rpc SubscribeRoutingStats(SubscribeRoutingStatsRequest)
returns (stream RoutingContext) {}
rpc TestRoute(TestRouteRequest) returns (RoutingContext) {}
}

View File

@ -11,7 +11,7 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
const _ = grpc.SupportPackageIsVersion7
// RoutingServiceClient is the client API for RoutingService service.
//
@ -83,13 +83,20 @@ type RoutingServiceServer interface {
type UnimplementedRoutingServiceServer struct {
}
func (*UnimplementedRoutingServiceServer) SubscribeRoutingStats(*SubscribeRoutingStatsRequest, RoutingService_SubscribeRoutingStatsServer) error {
func (UnimplementedRoutingServiceServer) SubscribeRoutingStats(*SubscribeRoutingStatsRequest, RoutingService_SubscribeRoutingStatsServer) error {
return status.Errorf(codes.Unimplemented, "method SubscribeRoutingStats not implemented")
}
func (*UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) {
func (UnimplementedRoutingServiceServer) TestRoute(context.Context, *TestRouteRequest) (*RoutingContext, error) {
return nil, status.Errorf(codes.Unimplemented, "method TestRoute not implemented")
}
func (*UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {}
func (UnimplementedRoutingServiceServer) mustEmbedUnimplementedRoutingServiceServer() {}
// UnsafeRoutingServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to RoutingServiceServer will
// result in compilation errors.
type UnsafeRoutingServiceServer interface {
mustEmbedUnimplementedRoutingServiceServer()
}
func RegisterRoutingServiceServer(s *grpc.Server, srv RoutingServiceServer) {
s.RegisterService(&_RoutingService_serviceDesc, srv)

View File

@ -21,9 +21,9 @@ import (
func TestServiceSubscribeRoutingStats(t *testing.T) {
c := stats.NewChannel(&stats.ChannelConfig{
SubscriberLimit: 1,
BufferSize: 16,
BroadcastTimeout: 100,
SubscriberLimit: 1,
BufferSize: 0,
Blocking: true,
})
common.Must(c.Start())
defer c.Close()
@ -55,122 +55,138 @@ func TestServiceSubscribeRoutingStats(t *testing.T) {
// Publisher goroutine
go func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
for { // Wait until there's one subscriber in routing stats channel
if len(c.Subscribers()) > 0 {
break
publishTestCases := func() error {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
for { // Wait until there's one subscriber in routing stats channel
if len(c.Subscribers()) > 0 {
break
}
if ctx.Err() != nil {
return ctx.Err()
}
}
if ctx.Err() != nil {
errCh <- ctx.Err()
for _, tc := range testCases {
c.Publish(context.Background(), AsRoutingRoute(tc))
time.Sleep(time.Millisecond)
}
return nil
}
for _, tc := range testCases {
c.Publish(AsRoutingRoute(tc))
if err := publishTestCases(); err != nil {
errCh <- err
}
// Wait for next round of publishing
<-nextPub
ctx, cancel = context.WithTimeout(context.Background(), time.Second)
defer cancel()
for { // Wait until there's one subscriber in routing stats channel
if len(c.Subscribers()) > 0 {
break
}
if ctx.Err() != nil {
errCh <- ctx.Err()
}
}
for _, tc := range testCases {
c.Publish(AsRoutingRoute(tc))
if err := publishTestCases(); err != nil {
errCh <- err
}
}()
// Client goroutine
go func() {
defer lis.Close()
conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
if err != nil {
errCh <- err
return
}
defer lis.Close()
defer conn.Close()
client := NewRoutingServiceClient(conn)
// Test retrieving all fields
streamCtx, streamClose := context.WithCancel(context.Background())
stream, err := client.SubscribeRoutingStats(streamCtx, &SubscribeRoutingStatsRequest{})
if err != nil {
errCh <- err
}
testRetrievingAllFields := func() error {
streamCtx, streamClose := context.WithCancel(context.Background())
for _, tc := range testCases {
msg, err := stream.Recv()
// Test the unsubscription of stream works well
defer func() {
streamClose()
timeOutCtx, timeout := context.WithTimeout(context.Background(), time.Second)
defer timeout()
for { // Wait until there's no subscriber in routing stats channel
if len(c.Subscribers()) == 0 {
break
}
if timeOutCtx.Err() != nil {
t.Error("unexpected subscribers not decreased in channel", timeOutCtx.Err())
}
}
}()
stream, err := client.SubscribeRoutingStats(streamCtx, &SubscribeRoutingStatsRequest{})
if err != nil {
errCh <- err
return err
}
if r := cmp.Diff(msg, tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
}
// Test that double subscription will fail
errStream, err := client.SubscribeRoutingStats(context.Background(), &SubscribeRoutingStatsRequest{
FieldSelectors: []string{"ip", "port", "domain", "outbound"},
})
if err != nil {
errCh <- err
}
if _, err := errStream.Recv(); err == nil {
t.Error("unexpected successful subscription")
}
for _, tc := range testCases {
msg, err := stream.Recv()
if err != nil {
return err
}
if r := cmp.Diff(msg, tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
}
// Test the unsubscription of stream works well
streamClose()
timeOutCtx, timeout := context.WithTimeout(context.Background(), time.Second)
defer timeout()
for { // Wait until there's no subscriber in routing stats channel
if len(c.Subscribers()) == 0 {
break
// Test that double subscription will fail
errStream, err := client.SubscribeRoutingStats(context.Background(), &SubscribeRoutingStatsRequest{
FieldSelectors: []string{"ip", "port", "domain", "outbound"},
})
if err != nil {
return err
}
if timeOutCtx.Err() != nil {
t.Error("unexpected subscribers not decreased in channel")
errCh <- timeOutCtx.Err()
if _, err := errStream.Recv(); err == nil {
t.Error("unexpected successful subscription")
}
return nil
}
// Test retrieving only a subset of fields
streamCtx, streamClose = context.WithCancel(context.Background())
stream, err = client.SubscribeRoutingStats(streamCtx, &SubscribeRoutingStatsRequest{
FieldSelectors: []string{"ip", "port", "domain", "outbound"},
})
if err != nil {
testRetrievingSubsetOfFields := func() error {
streamCtx, streamClose := context.WithCancel(context.Background())
defer streamClose()
stream, err := client.SubscribeRoutingStats(streamCtx, &SubscribeRoutingStatsRequest{
FieldSelectors: []string{"ip", "port", "domain", "outbound"},
})
if err != nil {
return err
}
// Send nextPub signal to start next round of publishing
close(nextPub)
for _, tc := range testCases {
msg, err := stream.Recv()
if err != nil {
return err
}
stat := &RoutingContext{ // Only a subset of stats is retrieved
SourceIPs: tc.SourceIPs,
TargetIPs: tc.TargetIPs,
SourcePort: tc.SourcePort,
TargetPort: tc.TargetPort,
TargetDomain: tc.TargetDomain,
OutboundGroupTags: tc.OutboundGroupTags,
OutboundTag: tc.OutboundTag,
}
if r := cmp.Diff(msg, stat, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
}
return nil
}
if err := testRetrievingAllFields(); err != nil {
errCh <- err
}
close(nextPub) // Send nextPub signal to start next round of publishing
for _, tc := range testCases {
msg, err := stream.Recv()
stat := &RoutingContext{ // Only a subset of stats is retrieved
SourceIPs: tc.SourceIPs,
TargetIPs: tc.TargetIPs,
SourcePort: tc.SourcePort,
TargetPort: tc.TargetPort,
TargetDomain: tc.TargetDomain,
OutboundGroupTags: tc.OutboundGroupTags,
OutboundTag: tc.OutboundTag,
}
if err != nil {
errCh <- err
}
if r := cmp.Diff(msg, stat, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
if err := testRetrievingSubsetOfFields(); err != nil {
errCh <- err
}
streamClose()
// Client passed all tests successfully
errCh <- nil
errCh <- nil // Client passed all tests successfully
}()
// Wait for goroutines to complete
@ -186,9 +202,9 @@ func TestServiceSubscribeRoutingStats(t *testing.T) {
func TestSerivceTestRoute(t *testing.T) {
c := stats.NewChannel(&stats.ChannelConfig{
SubscriberLimit: 1,
BufferSize: 16,
BroadcastTimeout: 100,
SubscriberLimit: 1,
BufferSize: 16,
Blocking: true,
})
common.Must(c.Start())
defer c.Close()
@ -249,11 +265,11 @@ func TestSerivceTestRoute(t *testing.T) {
// Client goroutine
go func() {
defer lis.Close()
conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
if err != nil {
errCh <- err
}
defer lis.Close()
defer conn.Close()
client := NewRoutingServiceClient(conn)
@ -268,58 +284,69 @@ func TestSerivceTestRoute(t *testing.T) {
}
// Test simple TestRoute
for _, tc := range testCases {
route, err := client.TestRoute(context.Background(), &TestRouteRequest{RoutingContext: tc})
if err != nil {
errCh <- err
}
if r := cmp.Diff(route, tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
testSimple := func() error {
for _, tc := range testCases {
route, err := client.TestRoute(context.Background(), &TestRouteRequest{RoutingContext: tc})
if err != nil {
return err
}
if r := cmp.Diff(route, tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
}
return nil
}
// Test TestRoute with special options
sub, err := c.Subscribe()
if err != nil {
errCh <- err
}
for _, tc := range testCases {
route, err := client.TestRoute(context.Background(), &TestRouteRequest{
RoutingContext: tc,
FieldSelectors: []string{"ip", "port", "domain", "outbound"},
PublishResult: true,
})
stat := &RoutingContext{ // Only a subset of stats is retrieved
SourceIPs: tc.SourceIPs,
TargetIPs: tc.TargetIPs,
SourcePort: tc.SourcePort,
TargetPort: tc.TargetPort,
TargetDomain: tc.TargetDomain,
OutboundGroupTags: tc.OutboundGroupTags,
OutboundTag: tc.OutboundTag,
}
testOptions := func() error {
sub, err := c.Subscribe()
if err != nil {
errCh <- err
return err
}
if r := cmp.Diff(route, stat, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
select { // Check that routing result has been published to statistics channel
case msg, received := <-sub:
if route, ok := msg.(routing.Route); received && ok {
if r := cmp.Diff(AsProtobufMessage(nil)(route), tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
} else {
t.Error("unexpected failure in receiving published routing result")
for _, tc := range testCases {
route, err := client.TestRoute(context.Background(), &TestRouteRequest{
RoutingContext: tc,
FieldSelectors: []string{"ip", "port", "domain", "outbound"},
PublishResult: true,
})
if err != nil {
return err
}
stat := &RoutingContext{ // Only a subset of stats is retrieved
SourceIPs: tc.SourceIPs,
TargetIPs: tc.TargetIPs,
SourcePort: tc.SourcePort,
TargetPort: tc.TargetPort,
TargetDomain: tc.TargetDomain,
OutboundGroupTags: tc.OutboundGroupTags,
OutboundTag: tc.OutboundTag,
}
if r := cmp.Diff(route, stat, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
select { // Check that routing result has been published to statistics channel
case msg, received := <-sub:
if route, ok := msg.(routing.Route); received && ok {
if r := cmp.Diff(AsProtobufMessage(nil)(route), tc, cmpopts.IgnoreUnexported(RoutingContext{})); r != "" {
t.Error(r)
}
} else {
t.Error("unexpected failure in receiving published routing result for testcase", tc)
}
case <-time.After(100 * time.Millisecond):
t.Error("unexpected failure in receiving published routing result", tc)
}
case <-time.After(100 * time.Millisecond):
t.Error("unexpected failure in receiving published routing result")
}
return nil
}
// Client passed all tests successfully
errCh <- nil
if err := testSimple(); err != nil {
errCh <- err
}
if err := testOptions(); err != nil {
errCh <- err
}
errCh <- nil // Client passed all tests successfully
}()
// Wait for goroutines to complete

View File

@ -484,12 +484,13 @@ type RoutingRule struct {
//
// Deprecated: Do not use.
Cidr []*CIDR `protobuf:"bytes,3,rep,name=cidr,proto3" json:"cidr,omitempty"`
// List of GeoIPs for target IP address matching. If this entry exists, the cidr above will have no effect.
// GeoIP fields with the same country code are supposed to contain exactly same content. They will be merged during runtime.
// For customized GeoIPs, please leave country code empty.
// List of GeoIPs for target IP address matching. If this entry exists, the
// cidr above will have no effect. GeoIP fields with the same country code are
// supposed to contain exactly same content. They will be merged during
// runtime. For customized GeoIPs, please leave country code empty.
Geoip []*GeoIP `protobuf:"bytes,10,rep,name=geoip,proto3" json:"geoip,omitempty"`
// A range of port [from, to]. If the destination port is in this range, this rule takes effect.
// Deprecated. Use port_list.
// A range of port [from, to]. If the destination port is in this range, this
// rule takes effect. Deprecated. Use port_list.
//
// Deprecated: Do not use.
PortRange *net.PortRange `protobuf:"bytes,4,opt,name=port_range,json=portRange,proto3" json:"port_range,omitempty"`
@ -505,7 +506,8 @@ type RoutingRule struct {
//
// Deprecated: Do not use.
SourceCidr []*CIDR `protobuf:"bytes,6,rep,name=source_cidr,json=sourceCidr,proto3" json:"source_cidr,omitempty"`
// List of GeoIPs for source IP address matching. If this entry exists, the source_cidr above will have no effect.
// List of GeoIPs for source IP address matching. If this entry exists, the
// source_cidr above will have no effect.
SourceGeoip []*GeoIP `protobuf:"bytes,11,rep,name=source_geoip,json=sourceGeoip,proto3" json:"source_geoip,omitempty"`
// List of ports for source port matching.
SourcePortList *net.PortList `protobuf:"bytes,16,opt,name=source_port_list,json=sourcePortList,proto3" json:"source_port_list,omitempty"`

View File

@ -65,7 +65,7 @@ message GeoSite {
repeated Domain domain = 2;
}
message GeoSiteList{
message GeoSiteList {
repeated GeoSite entry = 1;
}
@ -78,7 +78,6 @@ message RoutingRule {
string balancing_tag = 12;
}
// List of domains for target domain matching.
repeated Domain domain = 2;
@ -86,13 +85,14 @@ message RoutingRule {
// Deprecated. Use geoip below.
repeated CIDR cidr = 3 [deprecated = true];
// List of GeoIPs for target IP address matching. If this entry exists, the cidr above will have no effect.
// GeoIP fields with the same country code are supposed to contain exactly same content. They will be merged during runtime.
// For customized GeoIPs, please leave country code empty.
// List of GeoIPs for target IP address matching. If this entry exists, the
// cidr above will have no effect. GeoIP fields with the same country code are
// supposed to contain exactly same content. They will be merged during
// runtime. For customized GeoIPs, please leave country code empty.
repeated GeoIP geoip = 10;
// A range of port [from, to]. If the destination port is in this range, this rule takes effect.
// Deprecated. Use port_list.
// A range of port [from, to]. If the destination port is in this range, this
// rule takes effect. Deprecated. Use port_list.
v2ray.core.common.net.PortRange port_range = 4 [deprecated = true];
// List of ports.
@ -107,7 +107,8 @@ message RoutingRule {
// List of CIDRs for source IP address matching.
repeated CIDR source_cidr = 6 [deprecated = true];
// List of GeoIPs for source IP address matching. If this entry exists, the source_cidr above will have no effect.
// List of GeoIPs for source IP address matching. If this entry exists, the
// source_cidr above will have no effect.
repeated GeoIP source_geoip = 11;
// List of ports for source port matching.

View File

@ -2,7 +2,7 @@
package router
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"

View File

@ -3,15 +3,15 @@
package stats
import (
"context"
"sync"
"time"
"v2ray.com/core/common"
)
// Channel is an implementation of stats.Channel.
type Channel struct {
channel chan interface{}
channel chan channelMessage
subscribers []chan interface{}
// Synchronization components
@ -19,28 +19,21 @@ type Channel struct {
closed chan struct{}
// Channel options
subscriberLimit int // Set to 0 as no subscriber limit
channelBufferSize int // Set to 0 as no buffering
broadcastTimeout time.Duration // Set to 0 as non-blocking immediate timeout
blocking bool // Set blocking state if channel buffer reaches limit
bufferSize int // Set to 0 as no buffering
subsLimit int // Set to 0 as no subscriber limit
}
// NewChannel creates an instance of Statistics Channel.
func NewChannel(config *ChannelConfig) *Channel {
return &Channel{
channel: make(chan interface{}, config.BufferSize),
subscriberLimit: int(config.SubscriberLimit),
channelBufferSize: int(config.BufferSize),
broadcastTimeout: time.Duration(config.BroadcastTimeout+1) * time.Millisecond,
channel: make(chan channelMessage, config.BufferSize),
subsLimit: int(config.SubscriberLimit),
bufferSize: int(config.BufferSize),
blocking: config.Blocking,
}
}
// Channel returns the underlying go channel.
func (c *Channel) Channel() chan interface{} {
c.access.RLock()
defer c.access.RUnlock()
return c.channel
}
// Subscribers implements stats.Channel.
func (c *Channel) Subscribers() []chan interface{} {
c.access.RLock()
@ -52,10 +45,10 @@ func (c *Channel) Subscribers() []chan interface{} {
func (c *Channel) Subscribe() (chan interface{}, error) {
c.access.Lock()
defer c.access.Unlock()
if c.subscriberLimit > 0 && len(c.subscribers) >= c.subscriberLimit {
if c.subsLimit > 0 && len(c.subscribers) >= c.subsLimit {
return nil, newError("Number of subscribers has reached limit")
}
subscriber := make(chan interface{}, c.channelBufferSize)
subscriber := make(chan interface{}, c.bufferSize)
c.subscribers = append(c.subscribers, subscriber)
return subscriber, nil
}
@ -77,16 +70,17 @@ func (c *Channel) Unsubscribe(subscriber chan interface{}) error {
}
// Publish implements stats.Channel.
func (c *Channel) Publish(message interface{}) {
func (c *Channel) Publish(ctx context.Context, msg interface{}) {
select { // Early exit if channel closed
case <-c.closed:
return
default:
}
select { // Drop message if not successfully sent
case c.channel <- message:
default:
return
pub := channelMessage{context: ctx, message: msg}
if c.blocking {
pub.publish(c.channel)
} else {
pub.publishNonBlocking(c.channel)
}
}
}
@ -111,13 +105,12 @@ func (c *Channel) Start() error {
go func() {
for {
select {
case message := <-c.channel: // Broadcast message
for _, sub := range c.Subscribers() { // Concurrency-safe subscribers retreivement
select {
case sub <- message: // Successfully sent message
case <-time.After(c.broadcastTimeout): // Remove timeout subscriber
common.Must(c.Unsubscribe(sub))
close(sub) // Actively close subscriber as notification
case pub := <-c.channel: // Published message received
for _, sub := range c.Subscribers() { // Concurrency-safe subscribers retrievement
if c.blocking {
pub.broadcast(sub)
} else {
pub.broadcastNonBlocking(sub)
}
}
case <-c.closed: // Channel closed
@ -142,3 +135,40 @@ func (c *Channel) Close() error {
}
return nil
}
// channelMessage is the published message with guaranteed delivery.
// message is discarded only when the context is early cancelled.
type channelMessage struct {
context context.Context
message interface{}
}
func (c channelMessage) publish(publisher chan channelMessage) {
select {
case publisher <- c:
case <-c.context.Done():
}
}
func (c channelMessage) publishNonBlocking(publisher chan channelMessage) {
select {
case publisher <- c:
default: // Create another goroutine to keep sending message
go c.publish(publisher)
}
}
func (c channelMessage) broadcast(subscriber chan interface{}) {
select {
case subscriber <- c.message:
case <-c.context.Done():
}
}
func (c channelMessage) broadcastNonBlocking(subscriber chan interface{}) {
select {
case subscriber <- c.message:
default: // Create another goroutine to keep sending message
go c.broadcast(subscriber)
}
}

View File

@ -1,6 +1,7 @@
package stats_test
import (
"context"
"fmt"
"testing"
"time"
@ -12,8 +13,7 @@ import (
func TestStatsChannel(t *testing.T) {
// At most 2 subscribers could be registered
c := NewChannel(&ChannelConfig{SubscriberLimit: 2})
source := c.Channel()
c := NewChannel(&ChannelConfig{SubscriberLimit: 2, Blocking: true})
a, err := stats.SubscribeRunnableChannel(c)
common.Must(err)
@ -34,21 +34,12 @@ func TestStatsChannel(t *testing.T) {
stopCh := make(chan struct{})
errCh := make(chan string)
go func() { // Blocking publish
source <- 1
source <- 2
source <- "3"
source <- []int{4}
source <- nil // Dummy messsage with no subscriber receiving, will block reading goroutine
for i := 0; i < cap(source); i++ {
source <- nil // Fill source channel's buffer
}
select {
case source <- nil: // Source writing should be blocked here, for last message was not cleared and buffer was full
errCh <- fmt.Sprint("unexpected non-blocked source channel")
default:
close(stopCh)
}
go func() {
c.Publish(context.Background(), 1)
c.Publish(context.Background(), 2)
c.Publish(context.Background(), "3")
c.Publish(context.Background(), []int{4})
stopCh <- struct{}{}
}()
go func() {
@ -64,6 +55,7 @@ func TestStatsChannel(t *testing.T) {
if v, ok := (<-a).([]int); !ok || v[0] != 4 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", []int{4})
}
stopCh <- struct{}{}
}()
go func() {
@ -79,14 +71,18 @@ func TestStatsChannel(t *testing.T) {
if v, ok := (<-b).([]int); !ok || v[0] != 4 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", []int{4})
}
stopCh <- struct{}{}
}()
select {
case <-time.After(2 * time.Second):
t.Fatal("Test timeout after 2s")
case e := <-errCh:
t.Fatal(e)
case <-stopCh:
timeout := time.After(2 * time.Second)
for i := 0; i < 3; i++ {
select {
case <-timeout:
t.Fatal("Test timeout after 2s")
case e := <-errCh:
t.Fatal(e)
case <-stopCh:
}
}
// Test the unsubscription of channel
@ -100,12 +96,10 @@ func TestStatsChannel(t *testing.T) {
}
func TestStatsChannelUnsubcribe(t *testing.T) {
c := NewChannel(&ChannelConfig{})
c := NewChannel(&ChannelConfig{Blocking: true})
common.Must(c.Start())
defer c.Close()
source := c.Channel()
a, err := c.Subscribe()
common.Must(err)
defer c.Unsubscribe(a)
@ -133,9 +127,9 @@ func TestStatsChannelUnsubcribe(t *testing.T) {
}
go func() { // Blocking publish
source <- 1
c.Publish(context.Background(), 1)
<-pauseCh // Wait for `b` goroutine to resume sending message
source <- 2
c.Publish(context.Background(), 2)
}()
go func() {
@ -151,7 +145,7 @@ func TestStatsChannelUnsubcribe(t *testing.T) {
if v, ok := (<-b).(int); !ok || v != 1 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 1)
}
// Unsubscribe `b` while `source`'s messaging is paused
// Unsubscribe `b` while publishing is paused
c.Unsubscribe(b)
{ // Test `b` is not in subscribers
var aSet, bSet bool
@ -167,7 +161,7 @@ func TestStatsChannelUnsubcribe(t *testing.T) {
errCh <- fmt.Sprint("unexpected subscribers: ", c.Subscribers())
}
}
// Resume `source`'s progress
// Resume publishing progress
close(pauseCh)
// Test `b` is neither closed nor able to receive any data
select {
@ -191,78 +185,142 @@ func TestStatsChannelUnsubcribe(t *testing.T) {
}
}
func TestStatsChannelTimeout(t *testing.T) {
func TestStatsChannelBlocking(t *testing.T) {
// Do not use buffer so as to create blocking scenario
c := NewChannel(&ChannelConfig{BufferSize: 0, BroadcastTimeout: 50})
c := NewChannel(&ChannelConfig{BufferSize: 0, Blocking: true})
common.Must(c.Start())
defer c.Close()
source := c.Channel()
a, err := c.Subscribe()
common.Must(err)
defer c.Unsubscribe(a)
b, err := c.Subscribe()
common.Must(err)
defer c.Unsubscribe(b)
pauseCh := make(chan struct{})
stopCh := make(chan struct{})
errCh := make(chan string)
go func() { // Blocking publish
source <- 1
source <- 2
ctx, cancel := context.WithCancel(context.Background())
// Test blocking channel publishing
go func() {
// Dummy messsage with no subscriber receiving, will block broadcasting goroutine
c.Publish(context.Background(), nil)
<-pauseCh
// Publishing should be blocked here, for last message was not cleared and buffer was full
c.Publish(context.Background(), nil)
pauseCh <- struct{}{}
// Publishing should still be blocked here
c.Publish(ctx, nil)
// Check publishing is done because context is canceled
select {
case <-ctx.Done():
if ctx.Err() != context.Canceled {
errCh <- fmt.Sprint("unexpected error: ", ctx.Err())
}
default:
errCh <- "unexpected non-blocked publishing"
}
close(stopCh)
}()
go func() {
if v, ok := (<-a).(int); !ok || v != 1 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 1)
pauseCh <- struct{}{}
select {
case <-pauseCh:
errCh <- "unexpected non-blocked publishing"
case <-time.After(100 * time.Millisecond):
}
if v, ok := (<-a).(int); !ok || v != 2 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 2)
// Receive first published message
<-a
select {
case <-pauseCh:
case <-time.After(100 * time.Millisecond):
errCh <- "unexpected blocking publishing"
}
{ // Test `b` is still in subscribers yet (because `a` receives 2 first)
var aSet, bSet bool
for _, s := range c.Subscribers() {
if s == a {
aSet = true
}
if s == b {
bSet = true
}
}
if !(aSet && bSet) {
errCh <- fmt.Sprint("unexpected subscribers: ", c.Subscribers())
// Manually cancel the context to end publishing
cancel()
}()
select {
case <-time.After(2 * time.Second):
t.Fatal("Test timeout after 2s")
case e := <-errCh:
t.Fatal(e)
case <-stopCh:
}
}
func TestStatsChannelNonBlocking(t *testing.T) {
// Do not use buffer so as to create blocking scenario
c := NewChannel(&ChannelConfig{BufferSize: 0, Blocking: false})
common.Must(c.Start())
defer c.Close()
a, err := c.Subscribe()
common.Must(err)
defer c.Unsubscribe(a)
pauseCh := make(chan struct{})
stopCh := make(chan struct{})
errCh := make(chan string)
ctx, cancel := context.WithCancel(context.Background())
// Test blocking channel publishing
go func() {
c.Publish(context.Background(), nil)
c.Publish(context.Background(), nil)
pauseCh <- struct{}{}
<-pauseCh
c.Publish(ctx, nil)
c.Publish(ctx, nil)
// Check publishing is done because context is canceled
select {
case <-ctx.Done():
if ctx.Err() != context.Canceled {
errCh <- fmt.Sprint("unexpected error: ", ctx.Err())
}
case <-time.After(100 * time.Millisecond):
errCh <- "unexpected non-cancelled publishing"
}
}()
go func() {
if v, ok := (<-b).(int); !ok || v != 1 {
errCh <- fmt.Sprint("unexpected receiving: ", v, ", wanted ", 1)
// Check publishing won't block even if there is no subscriber receiving message
select {
case <-pauseCh:
case <-time.After(100 * time.Millisecond):
errCh <- "unexpected blocking publishing"
}
// Block `b` channel for a time longer than `source`'s timeout
<-time.After(200 * time.Millisecond)
{ // Test `b` has been unsubscribed by source
var aSet, bSet bool
for _, s := range c.Subscribers() {
if s == a {
aSet = true
}
if s == b {
bSet = true
}
}
if !(aSet && !bSet) {
errCh <- fmt.Sprint("unexpected subscribers: ", c.Subscribers())
}
// Receive first and second published message
<-a
<-a
pauseCh <- struct{}{}
// Manually cancel the context to end publishing
cancel()
// Check third and forth published message is cancelled and cannot receive
<-time.After(100 * time.Millisecond)
select {
case <-a:
errCh <- "unexpected non-cancelled publishing"
default:
}
select { // Test `b` has been closed by source
case v, ok := <-b:
if ok {
errCh <- fmt.Sprint("unexpected data received: ", v)
}
select {
case <-a:
errCh <- "unexpected non-cancelled publishing"
default:
}
close(stopCh)
@ -279,12 +337,10 @@ func TestStatsChannelTimeout(t *testing.T) {
func TestStatsChannelConcurrency(t *testing.T) {
// Do not use buffer so as to create blocking scenario
c := NewChannel(&ChannelConfig{BufferSize: 0, BroadcastTimeout: 100})
c := NewChannel(&ChannelConfig{BufferSize: 0, Blocking: true})
common.Must(c.Start())
defer c.Close()
source := c.Channel()
a, err := c.Subscribe()
common.Must(err)
defer c.Unsubscribe(a)
@ -297,8 +353,8 @@ func TestStatsChannelConcurrency(t *testing.T) {
errCh := make(chan string)
go func() { // Blocking publish
source <- 1
source <- 2
c.Publish(context.Background(), 1)
c.Publish(context.Background(), 2)
}()
go func() {
@ -311,8 +367,7 @@ func TestStatsChannelConcurrency(t *testing.T) {
}()
go func() {
// Block `b` for a time shorter than `source`'s timeout
// So as to ensure source channel is trying to send message to `b`.
// Block `b` for a time so as to ensure source channel is trying to send message to `b`.
<-time.After(25 * time.Millisecond)
// This causes concurrency scenario: unsubscribe `b` while trying to send message to it
c.Unsubscribe(b)
@ -327,11 +382,11 @@ func TestStatsChannelConcurrency(t *testing.T) {
errCh <- fmt.Sprint("unexpected block from receiving data: ", 1)
}
// Test `b` is not closed but cannot receive data 2:
// Becuase in a new round of messaging, `b` has been unsubscribed.
// Because in a new round of messaging, `b` has been unsubscribed.
select {
case v, ok := <-b:
if ok {
errCh <- fmt.Sprint("unexpected receving: ", v)
errCh <- fmt.Sprint("unexpected receiving: ", v)
} else {
errCh <- fmt.Sprint("unexpected closing of channel")
}

View File

@ -2,7 +2,7 @@
package command
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"

View File

@ -31,8 +31,7 @@ message QueryStatsResponse {
repeated Stat stat = 1;
}
message SysStatsRequest {
}
message SysStatsRequest {}
message SysStatsResponse {
uint32 NumGoroutine = 1;

View File

@ -11,7 +11,7 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
const _ = grpc.SupportPackageIsVersion7
// StatsServiceClient is the client API for StatsService service.
//
@ -71,16 +71,23 @@ type StatsServiceServer interface {
type UnimplementedStatsServiceServer struct {
}
func (*UnimplementedStatsServiceServer) GetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error) {
func (UnimplementedStatsServiceServer) GetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetStats not implemented")
}
func (*UnimplementedStatsServiceServer) QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error) {
func (UnimplementedStatsServiceServer) QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method QueryStats not implemented")
}
func (*UnimplementedStatsServiceServer) GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error) {
func (UnimplementedStatsServiceServer) GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetSysStats not implemented")
}
func (*UnimplementedStatsServiceServer) mustEmbedUnimplementedStatsServiceServer() {}
func (UnimplementedStatsServiceServer) mustEmbedUnimplementedStatsServiceServer() {}
// UnsafeStatsServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to StatsServiceServer will
// result in compilation errors.
type UnsafeStatsServiceServer interface {
mustEmbedUnimplementedStatsServiceServer()
}
func RegisterStatsServiceServer(s *grpc.Server, srv StatsServiceServer) {
s.RegisterService(&_StatsService_serviceDesc, srv)

View File

@ -68,9 +68,9 @@ type ChannelConfig struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
SubscriberLimit int32 `protobuf:"varint,1,opt,name=SubscriberLimit,proto3" json:"SubscriberLimit,omitempty"`
BufferSize int32 `protobuf:"varint,2,opt,name=BufferSize,proto3" json:"BufferSize,omitempty"`
BroadcastTimeout int32 `protobuf:"varint,3,opt,name=BroadcastTimeout,proto3" json:"BroadcastTimeout,omitempty"`
Blocking bool `protobuf:"varint,1,opt,name=Blocking,proto3" json:"Blocking,omitempty"`
SubscriberLimit int32 `protobuf:"varint,2,opt,name=SubscriberLimit,proto3" json:"SubscriberLimit,omitempty"`
BufferSize int32 `protobuf:"varint,3,opt,name=BufferSize,proto3" json:"BufferSize,omitempty"`
}
func (x *ChannelConfig) Reset() {
@ -105,6 +105,13 @@ func (*ChannelConfig) Descriptor() ([]byte, []int) {
return file_app_stats_config_proto_rawDescGZIP(), []int{1}
}
func (x *ChannelConfig) GetBlocking() bool {
if x != nil {
return x.Blocking
}
return false
}
func (x *ChannelConfig) GetSubscriberLimit() int32 {
if x != nil {
return x.SubscriberLimit
@ -119,34 +126,26 @@ func (x *ChannelConfig) GetBufferSize() int32 {
return 0
}
func (x *ChannelConfig) GetBroadcastTimeout() int32 {
if x != nil {
return x.BroadcastTimeout
}
return 0
}
var File_app_stats_config_proto protoreflect.FileDescriptor
var file_app_stats_config_proto_rawDesc = []byte{
0x0a, 0x16, 0x61, 0x70, 0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x22, 0x08,
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x85, 0x01, 0x0a, 0x0d, 0x43, 0x68, 0x61,
0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x53, 0x75,
0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0f, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x4c,
0x69, 0x6d, 0x69, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69,
0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72,
0x53, 0x69, 0x7a, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73,
0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10,
0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
0x42, 0x4d, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x50, 0x01, 0x5a, 0x18,
0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61,
0x70, 0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0xaa, 0x02, 0x14, 0x56, 0x32, 0x52, 0x61, 0x79,
0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x75, 0x0a, 0x0d, 0x43, 0x68, 0x61, 0x6e,
0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
0x62, 0x65, 0x72, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f,
0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12,
0x1e, 0x0a, 0x0a, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0a, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x42,
0x4d, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72,
0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x73, 0x50, 0x01, 0x5a, 0x18, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
0x70, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0xaa, 0x02, 0x14, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e,
0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -6,12 +6,10 @@ option go_package = "v2ray.com/core/app/stats";
option java_package = "com.v2ray.core.app.stats";
option java_multiple_files = true;
message Config {
}
message Config {}
message ChannelConfig {
int32 SubscriberLimit = 1;
int32 BufferSize = 2;
int32 BroadcastTimeout = 3;
bool Blocking = 1;
int32 SubscriberLimit = 2;
int32 BufferSize = 3;
}

View File

@ -2,7 +2,7 @@
package stats
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"context"
@ -94,7 +94,7 @@ func (m *Manager) RegisterChannel(name string) (stats.Channel, error) {
return nil, newError("Channel ", name, " already registered.")
}
newError("create new channel ", name).AtDebug().WriteToLog()
c := NewChannel(&ChannelConfig{BufferSize: 16, BroadcastTimeout: 100})
c := NewChannel(&ChannelConfig{BufferSize: 64, Blocking: false})
m.channels[name] = c
if m.running {
return c, c.Start()

View File

@ -7,68 +7,32 @@ trigger:
- refs/tags/*
pool:
vmImage: 'ubuntu-latest'
vmImage: "ubuntu-latest"
variables:
- group: GithubToken
- name: GOPATH
value: '$(system.defaultWorkingDirectory)/gopath'
- name: BAZEL_VER
value: '3.5.0'
steps:
- checkout: self
- task: GoTool@0
inputs:
version: '1.15.2'
- script: |
mkdir triggersrc
ls -I "triggersrc" | xargs cp -rf -t triggersrc
mkdir gopath
displayName: Prepare Environment
workingDirectory: '$(system.defaultWorkingDirectory)'
- script: |
sudo apt-get -y update
sudo apt-get -y install jq git file pkg-config zip g++ zlib1g-dev unzip python openssl tree
displayName: Apt Install
version: "1.15.2"
- script: |
go version
unset GOPATH
mkdir ./src
mkdir ./src/v2ray.com
ln -s $(pwd)/../triggersrc ./src/v2ray.com/core
go get -v -t -d ./src/v2ray.com/core/...
tree
workingDirectory: '$(GOPATH)'
displayName: 'Fetch sources'
go mod download
workingDirectory: $(system.defaultWorkingDirectory)
displayName: "Fetch sources"
- script: |
mkdir release
cd src
zip -9 -r ../release/src_all.zip * -x '*.git*'
workingDirectory: '$(GOPATH)'
displayName: 'Dump sources'
bazel build --action_env=PATH=$PATH --action_env=GOPATH=$(go env GOPATH) --action_env=GOCACHE=$(go env GOCACHE) --action_env=SPWD=$(pwd) --spawn_strategy local //release:all
workingDirectory: $(system.defaultWorkingDirectory)
displayName: "Build Binaries"
- script: |
curl -L -o bazel-installer.sh https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VER}/bazel-${BAZEL_VER}-installer-linux-x86_64.sh
chmod +x bazel-installer.sh
./bazel-installer.sh --user
workingDirectory: '$(GOPATH)'
displayName: 'Install Bazel'
- script: |
cd ./src/v2ray.com/core
$HOME/bin/bazel build --action_env=GOPATH=$GOPATH --action_env=PATH=$PATH --action_env=GPG_PASS=${SIGN_KEY_PASS} --action_env=SPWD=$PWD --action_env=GOCACHE=$(go env GOCACHE) --spawn_strategy local //release:all
workingDirectory: '$(GOPATH)'
displayName: 'Build Binaries'
- script: |
cp ./src/v2ray.com/core/bazel-bin/release/*.zip ./release/
workingDirectory: '$(GOPATH)'
displayName: 'Dump Binaries'
- script: |
cd ./src/v2ray.com/core
echo $RELEASE_TAG
./release/bleedingrelease.sh
workingDirectory: '$(GOPATH)'
displayName: 'Generate Bleeding Edge Release'
workingDirectory: $(system.defaultWorkingDirectory)
displayName: "Generate Bleeding Edge Release"
env:
WORKDIR: $(system.defaultWorkingDirectory)
GITHUB_TOKEN: $(GITHUB_TOKEN)
PRERELEASE: true
RELEASE_TAG: unstable-$(Build.SourceVersion)
@ -77,13 +41,14 @@ steps:
GITHUB_REPO_OWNER: v2fly
GITHUB_REPO_NAME: v2ray-core
- script: |
cd ./src/v2ray.com/core
echo $RELEASE_TAG
./release/tagrelease.sh
workingDirectory: '$(GOPATH)'
displayName: 'Generate Tag Release'
workingDirectory: $(system.defaultWorkingDirectory)
displayName: "Generate Tag Release"
env:
WORKDIR: $(system.defaultWorkingDirectory)
GITHUB_TOKEN: $(GITHUB_TOKEN)
PRERELEASE: true
RELEASE_TAG: unstable-$(Build.SourceVersion)
RELEASE_SHA: $(Build.SourceVersion)
TRIGGER_REASON: $(Build.SourceBranch)

View File

@ -1,4 +1,4 @@
// Package buf provides a light-weight memory allocation mechanism.
package buf // import "v2ray.com/core/common/buf"
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen

View File

@ -13,7 +13,7 @@ import (
"v2ray.com/core/common/errors"
)
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
var (
// ErrNoClue is for the situation that existing information is not enough to make a decision. For example, Router may return this error when there is no suitable route.
@ -125,26 +125,34 @@ func GetGOPATH() string {
}
// GetModuleName returns the value of module in `go.mod` file.
func GetModuleName(path string) (string, error) {
gomodPath := filepath.Join(path, "go.mod")
gomodBytes, err := ioutil.ReadFile(gomodPath)
if err != nil {
return "", err
}
gomodContent := string(gomodBytes)
moduleIdx := strings.Index(gomodContent, "module") + 6
newLineIdx := strings.Index(gomodContent, "\n")
func GetModuleName(pathToProjectRoot string) (string, error) {
var moduleName string
if moduleIdx >= 0 {
if newLineIdx >= 0 {
moduleName = strings.TrimSpace(gomodContent[moduleIdx:newLineIdx])
moduleName = strings.TrimSuffix(moduleName, "\r")
} else {
moduleName = strings.TrimSpace(gomodContent[moduleIdx:])
loopPath := pathToProjectRoot
for {
if idx := strings.LastIndex(loopPath, string(filepath.Separator)); idx >= 0 {
gomodPath := filepath.Join(loopPath, "go.mod")
gomodBytes, err := ioutil.ReadFile(gomodPath)
if err != nil {
loopPath = loopPath[:idx]
continue
}
gomodContent := string(gomodBytes)
moduleIdx := strings.Index(gomodContent, "module ")
newLineIdx := strings.Index(gomodContent, "\n")
if moduleIdx >= 0 {
if newLineIdx >= 0 {
moduleName = strings.TrimSpace(gomodContent[moduleIdx+6 : newLineIdx])
moduleName = strings.TrimSuffix(moduleName, "\r")
} else {
moduleName = strings.TrimSpace(gomodContent[moduleIdx+6:])
}
return moduleName, nil
}
return "", fmt.Errorf("can not get module path in `%s`", gomodPath)
}
} else {
return "", fmt.Errorf("can not get the value of `module` in path `%s`", gomodPath)
break
}
return moduleName, nil
return moduleName, fmt.Errorf("no `go.mod` file in every parent directory of `%s`", pathToProjectRoot)
}

View File

@ -1,4 +1,4 @@
// Package crypto provides common crypto libraries for V2Ray.
package crypto // import "v2ray.com/core/common/crypto"
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen

View File

@ -5,35 +5,41 @@ import (
"log"
"os"
"path/filepath"
"v2ray.com/core/common"
)
func getCurrentPkg() (string, error) {
path, err := os.Getwd()
if err != nil {
return "", err
}
return filepath.Base(path), nil
}
func main() {
pkg, err := getCurrentPkg()
pwd, err := os.Getwd()
if err != nil {
log.Fatal("Failed to get current package: ", err.Error())
return
fmt.Println("can not get current working directory")
os.Exit(1)
}
pkg := filepath.Base(pwd)
if pkg == "v2ray-core" {
pkg = "core"
}
moduleName, gmnErr := common.GetModuleName(pwd)
if gmnErr != nil {
fmt.Println("can not get module path", gmnErr)
os.Exit(1)
}
file, err := os.OpenFile("errors.generated.go", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
if err != nil {
log.Fatalf("Failed to generate errors.generated.go: %v", err)
return
os.Exit(1)
}
defer file.Close()
fmt.Fprintln(file, "package", pkg)
fmt.Fprintln(file, "")
fmt.Fprintln(file, "import \"v2ray.com/core/common/errors\"")
fmt.Fprintln(file, "import \""+moduleName+"/common/errors\"")
fmt.Fprintln(file, "")
fmt.Fprintln(file, "type errPathObjHolder struct {}")
fmt.Fprintln(file, "func newError(values ...interface{}) *errors.Error { return errors.New(values...).WithPathObj(errPathObjHolder{}) }")
file.Close()
fmt.Fprintln(file, "type errPathObjHolder struct{}")
fmt.Fprintln(file, "")
fmt.Fprintln(file, "func newError(values ...interface{}) *errors.Error {")
fmt.Fprintln(file, " return errors.New(values...).WithPathObj(errPathObjHolder{})")
fmt.Fprintln(file, "}")
}

View File

@ -1,3 +1,3 @@
package mux
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen

View File

@ -25,7 +25,8 @@ const (
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// Address of a network host. It may be either an IP address or a domain address.
// Address of a network host. It may be either an IP address or a domain
// address.
type IPOrDomain struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache

View File

@ -6,7 +6,8 @@ option go_package = "v2ray.com/core/common/net";
option java_package = "com.v2ray.core.common.net";
option java_multiple_files = true;
// Address of a network host. It may be either an IP address or a domain address.
// Address of a network host. It may be either an IP address or a domain
// address.
message IPOrDomain {
oneof address {
// IP address. Must by either 4 or 16 bytes.

View File

@ -1,4 +1,4 @@
// Package net is a drop-in replacement to Golang's net package, with some more functionalities.
package net // import "v2ray.com/core/common/net"
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen

View File

@ -9,7 +9,7 @@ option java_multiple_files = true;
enum Network {
Unknown = 0;
RawTCP = 1 [deprecated=true];
RawTCP = 1 [deprecated = true];
TCP = 2;
UDP = 3;
}

View File

@ -10,7 +10,7 @@ import (
"v2ray.com/core/common/platform"
)
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
func Run(args []string, input io.Reader) (buf.MultiBuffer, error) {
v2ctl := platform.GetToolLocation("v2ctl")

View File

@ -1,3 +1,3 @@
package protocol // import "v2ray.com/core/common/protocol"
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen

View File

@ -15,7 +15,7 @@ import (
"v2ray.com/core/common"
)
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
type Certificate struct {
// Cerificate in ASN.1 DER format

View File

@ -34,7 +34,8 @@ type User struct {
Level uint32 `protobuf:"varint,1,opt,name=level,proto3" json:"level,omitempty"`
Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"`
// Protocol specific account information. Must be the account proto in one of the proxies.
// Protocol specific account information. Must be the account proto in one of
// the proxies.
Account *serial.TypedMessage `protobuf:"bytes,3,opt,name=account,proto3" json:"account,omitempty"`
}

View File

@ -13,6 +13,7 @@ message User {
uint32 level = 1;
string email = 2;
// Protocol specific account information. Must be the account proto in one of the proxies.
// Protocol specific account information. Must be the account proto in one of
// the proxies.
v2ray.core.common.serial.TypedMessage account = 3;
}

View File

@ -1,6 +1,6 @@
package retry // import "v2ray.com/core/common/retry"
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"time"

View File

@ -10,6 +10,6 @@ option java_multiple_files = true;
message TypedMessage {
// The name of the message type, retrieved from protobuf API.
string type = 1;
// Serialized proto message.
// Serialized proto message.
bytes value = 2;
}

View File

@ -27,7 +27,8 @@ const (
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// Config is the master config of V2Ray. V2Ray takes this config as input and functions accordingly.
// Config is the master config of V2Ray. V2Ray takes this config as input and
// functions accordingly.
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -35,18 +36,22 @@ type Config struct {
// Inbound handler configurations. Must have at least one item.
Inbound []*InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbound,proto3" json:"inbound,omitempty"`
// Outbound handler configurations. Must have at least one item. The first item is used as default for routing.
// Outbound handler configurations. Must have at least one item. The first
// item is used as default for routing.
Outbound []*OutboundHandlerConfig `protobuf:"bytes,2,rep,name=outbound,proto3" json:"outbound,omitempty"`
// App is for configurations of all features in V2Ray. A feature must implement the Feature interface, and its config type must be registered through common.RegisterConfig.
// App is for configurations of all features in V2Ray. A feature must
// implement the Feature interface, and its config type must be registered
// through common.RegisterConfig.
App []*serial.TypedMessage `protobuf:"bytes,4,rep,name=app,proto3" json:"app,omitempty"`
// Transport settings.
// Deprecated. Each inbound and outbound should choose their own transport config.
// Date to remove: 2020-01-13
// Deprecated. Each inbound and outbound should choose their own transport
// config. Date to remove: 2020-01-13
//
// Deprecated: Do not use.
Transport *transport.Config `protobuf:"bytes,5,opt,name=transport,proto3" json:"transport,omitempty"`
// Configuration for extensions. The config may not work if corresponding extension is not loaded into V2Ray.
// V2Ray will ignore such config during initialization.
// Configuration for extensions. The config may not work if corresponding
// extension is not loaded into V2Ray. V2Ray will ignore such config during
// initialization.
Extension []*serial.TypedMessage `protobuf:"bytes,6,rep,name=extension,proto3" json:"extension,omitempty"`
}
@ -124,7 +129,8 @@ type InboundHandlerConfig struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Tag of the inbound handler. The tag must be unique among all inbound handlers
// Tag of the inbound handler. The tag must be unique among all inbound
// handlers
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
// Settings for how this inbound proxy is handled.
ReceiverSettings *serial.TypedMessage `protobuf:"bytes,2,opt,name=receiver_settings,json=receiverSettings,proto3" json:"receiver_settings,omitempty"`

View File

@ -9,32 +9,38 @@ option java_multiple_files = true;
import "common/serial/typed_message.proto";
import "transport/config.proto";
// Config is the master config of V2Ray. V2Ray takes this config as input and functions accordingly.
// Config is the master config of V2Ray. V2Ray takes this config as input and
// functions accordingly.
message Config {
// Inbound handler configurations. Must have at least one item.
repeated InboundHandlerConfig inbound = 1;
// Outbound handler configurations. Must have at least one item. The first item is used as default for routing.
// Outbound handler configurations. Must have at least one item. The first
// item is used as default for routing.
repeated OutboundHandlerConfig outbound = 2;
reserved 3;
// App is for configurations of all features in V2Ray. A feature must implement the Feature interface, and its config type must be registered through common.RegisterConfig.
// App is for configurations of all features in V2Ray. A feature must
// implement the Feature interface, and its config type must be registered
// through common.RegisterConfig.
repeated v2ray.core.common.serial.TypedMessage app = 4;
// Transport settings.
// Deprecated. Each inbound and outbound should choose their own transport config.
// Date to remove: 2020-01-13
// Deprecated. Each inbound and outbound should choose their own transport
// config. Date to remove: 2020-01-13
v2ray.core.transport.Config transport = 5 [deprecated = true];
// Configuration for extensions. The config may not work if corresponding extension is not loaded into V2Ray.
// V2Ray will ignore such config during initialization.
// Configuration for extensions. The config may not work if corresponding
// extension is not loaded into V2Ray. V2Ray will ignore such config during
// initialization.
repeated v2ray.core.common.serial.TypedMessage extension = 6;
}
// InboundHandlerConfig is the configuration for inbound handler.
message InboundHandlerConfig {
// Tag of the inbound handler. The tag must be unique among all inbound handlers
// Tag of the inbound handler. The tag must be unique among all inbound
// handlers
string tag = 1;
// Settings for how this inbound proxy is handled.
v2ray.core.common.serial.TypedMessage receiver_settings = 2;

View File

@ -9,8 +9,7 @@
// connections.
package core
//go:generate go install "v2ray.com/core/common/errors/errorgen"
//go:generate errorgen
//go:generate go run v2ray.com/core/common/errors/errorgen
import (
"runtime"
@ -19,7 +18,7 @@ import (
)
var (
version = "4.30.0"
version = "4.31.0"
build = "Custom"
codename = "V2Fly, a community-driven edition of V2Ray."
intro = "A unified platform for anti-censorship."

7
external/README.md vendored
View File

@ -1,7 +0,0 @@
# Note
The `external` dir in the project exists for historical reasons. We will migrate to use go mod to maintain 3rd party libraries.
Fow now, all modules under external are used by "quic-go" to support quic protocol, and can't migrate without a breaking change.
The plan is that we will remove the whole `external` dir when `quic-go` is tested to be matured enough in production.

View File

@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 cheekybits
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,2 +0,0 @@
// Package generic contains the generic marker types.
package generic

View File

@ -1,13 +0,0 @@
package generic
// Type is the placeholder type that indicates a generic value.
// When genny is executed, variables of this type will be replaced with
// references to the specific types.
// var GenericType generic.Type
type Type interface{}
// Number is the placehoder type that indiccates a generic numerical value.
// When genny is executed, variables of this type will be replaced with
// references to the specific types.
// var GenericType generic.Number
type Number float64

View File

@ -1,57 +0,0 @@
Copyright (c) 2017 Cloudflare. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Cloudflare nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
========================================================================
The x64 field arithmetic implementation was derived from the Microsoft Research
SIDH implementation, <https://github.com/Microsoft/PQCrypto-SIDH>, available
under the following license:
========================================================================
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

View File

@ -1,66 +0,0 @@
// +build noasm !amd64
package internal
// helper used for Uint128 representation
type Uint128 struct {
H, L uint64
}
// Adds 2 64bit digits in constant time.
// Returns result and carry (1 or 0)
func Addc64(cin, a, b uint64) (ret, cout uint64) {
t := a + cin
ret = b + t
cout = ((a & b) | ((a | b) & (^ret))) >> 63
return
}
// Substracts 2 64bit digits in constant time.
// Returns result and borrow (1 or 0)
func Subc64(bIn, a, b uint64) (ret, bOut uint64) {
var tmp1 = a - b
// Set bOut if bIn!=0 and tmp1==0 in constant time
bOut = bIn & (1 ^ ((tmp1 | uint64(0-tmp1)) >> 63))
// Constant time check if x<y
bOut |= (a ^ ((a ^ b) | (uint64(a-b) ^ b))) >> 63
ret = tmp1 - bIn
return
}
// Multiplies 2 64bit digits in constant time
func Mul64(a, b uint64) (res Uint128) {
var al, bl, ah, bh, albl, albh, ahbl, ahbh uint64
var res1, res2, res3 uint64
var carry, maskL, maskH, temp uint64
maskL = (^maskL) >> 32
maskH = ^maskL
al = a & maskL
ah = a >> 32
bl = b & maskL
bh = b >> 32
albl = al * bl
albh = al * bh
ahbl = ah * bl
ahbh = ah * bh
res.L = albl & maskL
res1 = albl >> 32
res2 = ahbl & maskL
res3 = albh & maskL
temp = res1 + res2 + res3
carry = temp >> 32
res.L ^= temp << 32
res1 = ahbl >> 32
res2 = albh >> 32
res3 = ahbh & maskL
temp = res1 + res2 + res3 + carry
res.H = temp & maskL
carry = temp & maskH
res.H ^= (ahbh & maskH) + carry
return
}

View File

@ -1,440 +0,0 @@
package internal
type CurveOperations struct {
Params *SidhParams
}
// Computes j-invariant for a curve y2=x3+A/Cx+x with A,C in F_(p^2). Result
// is returned in jBytes buffer, encoded in little-endian format. Caller
// provided jBytes buffer has to be big enough to j-invariant value. In case
// of SIDH, buffer size must be at least size of shared secret.
// Implementation corresponds to Algorithm 9 from SIKE.
func (c *CurveOperations) Jinvariant(cparams *ProjectiveCurveParameters, jBytes []byte) {
var j, t0, t1 Fp2Element
op := c.Params.Op
op.Square(&j, &cparams.A) // j = A^2
op.Square(&t1, &cparams.C) // t1 = C^2
op.Add(&t0, &t1, &t1) // t0 = t1 + t1
op.Sub(&t0, &j, &t0) // t0 = j - t0
op.Sub(&t0, &t0, &t1) // t0 = t0 - t1
op.Sub(&j, &t0, &t1) // t0 = t0 - t1
op.Square(&t1, &t1) // t1 = t1^2
op.Mul(&j, &j, &t1) // j = j * t1
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
op.Square(&t1, &t0) // t1 = t0^2
op.Mul(&t0, &t0, &t1) // t0 = t0 * t1
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
op.Inv(&j, &j) // j = 1/j
op.Mul(&j, &t0, &j) // j = t0 * j
c.Fp2ToBytes(jBytes, &j)
}
// Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function
// recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE.
func (c *CurveOperations) RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2Element) {
var t0, t1 Fp2Element
op := c.Params.Op
op.Add(&t1, xp, xq) // t1 = Xp + Xq
op.Mul(&t0, xp, xq) // t0 = Xp * Xq
op.Mul(&curve.A, xr, &t1) // A = X(q-p) * t1
op.Add(&curve.A, &curve.A, &t0) // A = A + t0
op.Mul(&t0, &t0, xr) // t0 = t0 * X(q-p)
op.Sub(&curve.A, &curve.A, &c.Params.OneFp2) // A = A - 1
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
op.Add(&t1, &t1, xr) // t1 = t1 + X(q-p)
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
op.Square(&curve.A, &curve.A) // A = A^2
op.Inv(&t0, &t0) // t0 = 1/t0
op.Mul(&curve.A, &curve.A, &t0) // A = A * t0
op.Sub(&curve.A, &curve.A, &t1) // A = A - t1
}
// Computes equivalence (A:C) ~ (A+2C : A-2C)
func (c *CurveOperations) CalcCurveParamsEquiv3(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
var coef CurveCoefficientsEquiv
var c2 Fp2Element
var op = c.Params.Op
op.Add(&c2, &cparams.C, &cparams.C)
// A24p = A+2*C
op.Add(&coef.A, &cparams.A, &c2)
// A24m = A-2*C
op.Sub(&coef.C, &cparams.A, &c2)
return coef
}
// Computes equivalence (A:C) ~ (A+2C : 4C)
func (c *CurveOperations) CalcCurveParamsEquiv4(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
var coefEq CurveCoefficientsEquiv
var op = c.Params.Op
op.Add(&coefEq.C, &cparams.C, &cparams.C)
// A24p = A+2C
op.Add(&coefEq.A, &cparams.A, &coefEq.C)
// C24 = 4*C
op.Add(&coefEq.C, &coefEq.C, &coefEq.C)
return coefEq
}
// Helper function for RightToLeftLadder(). Returns A+2C / 4.
func (c *CurveOperations) CalcAplus2Over4(cparams *ProjectiveCurveParameters) (ret Fp2Element) {
var tmp Fp2Element
var op = c.Params.Op
// 2C
op.Add(&tmp, &cparams.C, &cparams.C)
// A+2C
op.Add(&ret, &cparams.A, &tmp)
// 1/4C
op.Add(&tmp, &tmp, &tmp)
op.Inv(&tmp, &tmp)
// A+2C/4C
op.Mul(&ret, &ret, &tmp)
return
}
// Recovers (A:C) curve parameters from projectively equivalent (A+2C:A-2C).
func (c *CurveOperations) RecoverCurveCoefficients3(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
var op = c.Params.Op
op.Add(&cparams.A, &coefEq.A, &coefEq.C)
// cparams.A = 2*(A+2C+A-2C) = 4A
op.Add(&cparams.A, &cparams.A, &cparams.A)
// cparams.C = (A+2C-A+2C) = 4C
op.Sub(&cparams.C, &coefEq.A, &coefEq.C)
return
}
// Recovers (A:C) curve parameters from projectively equivalent (A+2C:4C).
func (c *CurveOperations) RecoverCurveCoefficients4(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
var op = c.Params.Op
// cparams.C = (4C)*1/2=2C
op.Mul(&cparams.C, &coefEq.C, &c.Params.HalfFp2)
// cparams.A = A+2C - 2C = A
op.Sub(&cparams.A, &coefEq.A, &cparams.C)
// cparams.C = 2C * 1/2 = C
op.Mul(&cparams.C, &cparams.C, &c.Params.HalfFp2)
return
}
// Combined coordinate doubling and differential addition. Takes projective points
// P,Q,Q-P and (A+2C)/4C curve E coefficient. Returns 2*P and P+Q calculated on E.
// Function is used only by RightToLeftLadder. Corresponds to Algorithm 5 of SIKE
func (c *CurveOperations) xDblAdd(P, Q, QmP *ProjectivePoint, a24 *Fp2Element) (dblP, PaQ ProjectivePoint) {
var t0, t1, t2 Fp2Element
var op = c.Params.Op
xQmP, zQmP := &QmP.X, &QmP.Z
xPaQ, zPaQ := &PaQ.X, &PaQ.Z
x2P, z2P := &dblP.X, &dblP.Z
xP, zP := &P.X, &P.Z
xQ, zQ := &Q.X, &Q.Z
op.Add(&t0, xP, zP) // t0 = Xp+Zp
op.Sub(&t1, xP, zP) // t1 = Xp-Zp
op.Square(x2P, &t0) // 2P.X = t0^2
op.Sub(&t2, xQ, zQ) // t2 = Xq-Zq
op.Add(xPaQ, xQ, zQ) // Xp+q = Xq+Zq
op.Mul(&t0, &t0, &t2) // t0 = t0 * t2
op.Mul(z2P, &t1, &t1) // 2P.Z = t1 * t1
op.Mul(&t1, &t1, xPaQ) // t1 = t1 * Xp+q
op.Sub(&t2, x2P, z2P) // t2 = 2P.X - 2P.Z
op.Mul(x2P, x2P, z2P) // 2P.X = 2P.X * 2P.Z
op.Mul(xPaQ, a24, &t2) // Xp+q = A24 * t2
op.Sub(zPaQ, &t0, &t1) // Zp+q = t0 - t1
op.Add(z2P, xPaQ, z2P) // 2P.Z = Xp+q + 2P.Z
op.Add(xPaQ, &t0, &t1) // Xp+q = t0 + t1
op.Mul(z2P, z2P, &t2) // 2P.Z = 2P.Z * t2
op.Square(zPaQ, zPaQ) // Zp+q = Zp+q ^ 2
op.Square(xPaQ, xPaQ) // Xp+q = Xp+q ^ 2
op.Mul(zPaQ, xQmP, zPaQ) // Zp+q = Xq-p * Zp+q
op.Mul(xPaQ, zQmP, xPaQ) // Xp+q = Zq-p * Xp+q
return
}
// Given the curve parameters, xP = x(P), computes xP = x([2^k]P)
// Safe to overlap xP, x2P.
func (c *CurveOperations) Pow2k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
var t0, t1 Fp2Element
var op = c.Params.Op
x, z := &xP.X, &xP.Z
for i := uint32(0); i < k; i++ {
op.Sub(&t0, x, z) // t0 = Xp - Zp
op.Add(&t1, x, z) // t1 = Xp + Zp
op.Square(&t0, &t0) // t0 = t0 ^ 2
op.Square(&t1, &t1) // t1 = t1 ^ 2
op.Mul(z, &params.C, &t0) // Z2p = C24 * t0
op.Mul(x, z, &t1) // X2p = Z2p * t1
op.Sub(&t1, &t1, &t0) // t1 = t1 - t0
op.Mul(&t0, &params.A, &t1) // t0 = A24+ * t1
op.Add(z, z, &t0) // Z2p = Z2p + t0
op.Mul(z, z, &t1) // Zp = Z2p * t1
}
}
// Given the curve parameters, xP = x(P), and k >= 0, compute xP = x([3^k]P).
//
// Safe to overlap xP, xR.
func (c *CurveOperations) Pow3k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
var t0, t1, t2, t3, t4, t5, t6 Fp2Element
var op = c.Params.Op
x, z := &xP.X, &xP.Z
for i := uint32(0); i < k; i++ {
op.Sub(&t0, x, z) // t0 = Xp - Zp
op.Square(&t2, &t0) // t2 = t0^2
op.Add(&t1, x, z) // t1 = Xp + Zp
op.Square(&t3, &t1) // t3 = t1^2
op.Add(&t4, &t1, &t0) // t4 = t1 + t0
op.Sub(&t0, &t1, &t0) // t0 = t1 - t0
op.Square(&t1, &t4) // t1 = t4^2
op.Sub(&t1, &t1, &t3) // t1 = t1 - t3
op.Sub(&t1, &t1, &t2) // t1 = t1 - t2
op.Mul(&t5, &t3, &params.A) // t5 = t3 * A24+
op.Mul(&t3, &t3, &t5) // t3 = t5 * t3
op.Mul(&t6, &t2, &params.C) // t6 = t2 * A24-
op.Mul(&t2, &t2, &t6) // t2 = t2 * t6
op.Sub(&t3, &t2, &t3) // t3 = t2 - t3
op.Sub(&t2, &t5, &t6) // t2 = t5 - t6
op.Mul(&t1, &t2, &t1) // t1 = t2 * t1
op.Add(&t2, &t3, &t1) // t2 = t3 + t1
op.Square(&t2, &t2) // t2 = t2^2
op.Mul(x, &t2, &t4) // X3p = t2 * t4
op.Sub(&t1, &t3, &t1) // t1 = t3 - t1
op.Square(&t1, &t1) // t1 = t1^2
op.Mul(z, &t1, &t0) // Z3p = t1 * t0
}
}
// Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3).
//
// All xi, yi must be distinct.
func (c *CurveOperations) Fp2Batch3Inv(x1, x2, x3, y1, y2, y3 *Fp2Element) {
var x1x2, t Fp2Element
var op = c.Params.Op
op.Mul(&x1x2, x1, x2) // x1*x2
op.Mul(&t, &x1x2, x3) // 1/(x1*x2*x3)
op.Inv(&t, &t)
op.Mul(y1, &t, x2) // 1/x1
op.Mul(y1, y1, x3)
op.Mul(y2, &t, x1) // 1/x2
op.Mul(y2, y2, x3)
op.Mul(y3, &t, &x1x2) // 1/x3
}
// ScalarMul3Pt is a right-to-left point multiplication that given the
// x-coordinate of P, Q and P-Q calculates the x-coordinate of R=Q+[scalar]P.
// nbits must be smaller or equal to len(scalar).
func (c *CurveOperations) ScalarMul3Pt(cparams *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint, nbits uint, scalar []uint8) ProjectivePoint {
var R0, R2, R1 ProjectivePoint
var op = c.Params.Op
aPlus2Over4 := c.CalcAplus2Over4(cparams)
R1 = *P
R2 = *PmQ
R0 = *Q
// Iterate over the bits of the scalar, bottom to top
prevBit := uint8(0)
for i := uint(0); i < nbits; i++ {
bit := (scalar[i>>3] >> (i & 7) & 1)
swap := prevBit ^ bit
prevBit = bit
op.CondSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, swap)
R0, R2 = c.xDblAdd(&R0, &R2, &R1, &aPlus2Over4)
}
op.CondSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, prevBit)
return R1
}
// Convert the input to wire format.
//
// The output byte slice must be at least 2*bytelen(p) bytes long.
func (c *CurveOperations) Fp2ToBytes(output []byte, fp2 *Fp2Element) {
if len(output) < 2*c.Params.Bytelen {
panic("output byte slice too short")
}
var a Fp2Element
c.Params.Op.FromMontgomery(fp2, &a)
// convert to bytes in little endian form
for i := 0; i < c.Params.Bytelen; i++ {
// set i = j*8 + k
fp2 := i / 8
k := uint64(i % 8)
output[i] = byte(a.A[fp2] >> (8 * k))
output[i+c.Params.Bytelen] = byte(a.B[fp2] >> (8 * k))
}
}
// Read 2*bytelen(p) bytes into the given ExtensionFieldElement.
//
// It is an error to call this function if the input byte slice is less than 2*bytelen(p) bytes long.
func (c *CurveOperations) Fp2FromBytes(fp2 *Fp2Element, input []byte) {
if len(input) < 2*c.Params.Bytelen {
panic("input byte slice too short")
}
for i := 0; i < c.Params.Bytelen; i++ {
j := i / 8
k := uint64(i % 8)
fp2.A[j] |= uint64(input[i]) << (8 * k)
fp2.B[j] |= uint64(input[i+c.Params.Bytelen]) << (8 * k)
}
c.Params.Op.ToMontgomery(fp2)
}
/* -------------------------------------------------------------------------
Mechnisms used for isogeny calculations
-------------------------------------------------------------------------*/
// Constructs isogeny3 objects
func Newisogeny3(op FieldOps) Isogeny {
return &isogeny3{Field: op}
}
// Constructs isogeny4 objects
func Newisogeny4(op FieldOps) Isogeny {
return &isogeny4{isogeny3: isogeny3{Field: op}}
}
// Given a three-torsion point p = x(PB) on the curve E_(A:C), construct the
// three-isogeny phi : E_(A:C) -> E_(A:C)/<P_3> = E_(A':C').
//
// Input: (XP_3: ZP_3), where P_3 has exact order 3 on E_A/C
// Output: * Curve coordinates (A' + 2C', A' - 2C') corresponding to E_A'/C' = A_E/C/<P3>
// * Isogeny phi with constants in F_p^2
func (phi *isogeny3) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv {
var t0, t1, t2, t3, t4 Fp2Element
var coefEq CurveCoefficientsEquiv
var K1, K2 = &phi.K1, &phi.K2
op := phi.Field
op.Sub(K1, &p.X, &p.Z) // K1 = XP3 - ZP3
op.Square(&t0, K1) // t0 = K1^2
op.Add(K2, &p.X, &p.Z) // K2 = XP3 + ZP3
op.Square(&t1, K2) // t1 = K2^2
op.Add(&t2, &t0, &t1) // t2 = t0 + t1
op.Add(&t3, K1, K2) // t3 = K1 + K2
op.Square(&t3, &t3) // t3 = t3^2
op.Sub(&t3, &t3, &t2) // t3 = t3 - t2
op.Add(&t2, &t1, &t3) // t2 = t1 + t3
op.Add(&t3, &t3, &t0) // t3 = t3 + t0
op.Add(&t4, &t3, &t0) // t4 = t3 + t0
op.Add(&t4, &t4, &t4) // t4 = t4 + t4
op.Add(&t4, &t1, &t4) // t4 = t1 + t4
op.Mul(&coefEq.C, &t2, &t4) // A24m = t2 * t4
op.Add(&t4, &t1, &t2) // t4 = t1 + t2
op.Add(&t4, &t4, &t4) // t4 = t4 + t4
op.Add(&t4, &t0, &t4) // t4 = t0 + t4
op.Mul(&t4, &t3, &t4) // t4 = t3 * t4
op.Sub(&t0, &t4, &coefEq.C) // t0 = t4 - A24m
op.Add(&coefEq.A, &coefEq.C, &t0) // A24p = A24m + t0
return coefEq
}
// Given a 3-isogeny phi and a point pB = x(PB), compute x(QB), the x-coordinate
// of the image QB = phi(PB) of PB under phi : E_(A:C) -> E_(A':C').
//
// The output xQ = x(Q) is then a point on the curve E_(A':C'); the curve
// parameters are returned by the GenerateCurve function used to construct phi.
func (phi *isogeny3) EvaluatePoint(p *ProjectivePoint) ProjectivePoint {
var t0, t1, t2 Fp2Element
var q ProjectivePoint
var K1, K2 = &phi.K1, &phi.K2
var px, pz = &p.X, &p.Z
op := phi.Field
op.Add(&t0, px, pz) // t0 = XQ + ZQ
op.Sub(&t1, px, pz) // t1 = XQ - ZQ
op.Mul(&t0, K1, &t0) // t2 = K1 * t0
op.Mul(&t1, K2, &t1) // t1 = K2 * t1
op.Add(&t2, &t0, &t1) // t2 = t0 + t1
op.Sub(&t0, &t1, &t0) // t0 = t1 - t0
op.Square(&t2, &t2) // t2 = t2 ^ 2
op.Square(&t0, &t0) // t0 = t0 ^ 2
op.Mul(&q.X, px, &t2) // XQ'= XQ * t2
op.Mul(&q.Z, pz, &t0) // ZQ'= ZQ * t0
return q
}
// Given a four-torsion point p = x(PB) on the curve E_(A:C), construct the
// four-isogeny phi : E_(A:C) -> E_(A:C)/<P_4> = E_(A':C').
//
// Input: (XP_4: ZP_4), where P_4 has exact order 4 on E_A/C
// Output: * Curve coordinates (A' + 2C', 4C') corresponding to E_A'/C' = A_E/C/<P4>
// * Isogeny phi with constants in F_p^2
func (phi *isogeny4) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv {
var coefEq CurveCoefficientsEquiv
var xp4, zp4 = &p.X, &p.Z
var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
op := phi.Field
op.Sub(K2, xp4, zp4)
op.Add(K3, xp4, zp4)
op.Square(K1, zp4)
op.Add(K1, K1, K1)
op.Square(&coefEq.C, K1)
op.Add(K1, K1, K1)
op.Square(&coefEq.A, xp4)
op.Add(&coefEq.A, &coefEq.A, &coefEq.A)
op.Square(&coefEq.A, &coefEq.A)
return coefEq
}
// Given a 4-isogeny phi and a point xP = x(P), compute x(Q), the x-coordinate
// of the image Q = phi(P) of P under phi : E_(A:C) -> E_(A':C').
//
// Input: Isogeny returned by GenerateCurve and point q=(Qx,Qz) from E0_A/C
// Output: Corresponding point q from E1_A'/C', where E1 is 4-isogenous to E0
func (phi *isogeny4) EvaluatePoint(p *ProjectivePoint) ProjectivePoint {
var t0, t1 Fp2Element
var q = *p
var xq, zq = &q.X, &q.Z
var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
op := phi.Field
op.Add(&t0, xq, zq)
op.Sub(&t1, xq, zq)
op.Mul(xq, &t0, K2)
op.Mul(zq, &t1, K3)
op.Mul(&t0, &t0, &t1)
op.Mul(&t0, &t0, K1)
op.Add(&t1, xq, zq)
op.Sub(zq, xq, zq)
op.Square(&t1, &t1)
op.Square(zq, zq)
op.Add(xq, &t0, &t1)
op.Sub(&t0, zq, &t0)
op.Mul(xq, xq, &t1)
op.Mul(zq, zq, &t0)
return q
}
/* -------------------------------------------------------------------------
Utils
-------------------------------------------------------------------------*/
func (point *ProjectivePoint) ToAffine(c *CurveOperations) *Fp2Element {
var affine_x Fp2Element
c.Params.Op.Inv(&affine_x, &point.Z)
c.Params.Op.Mul(&affine_x, &affine_x, &point.X)
return &affine_x
}
// Cleans data in fp
func (fp *Fp2Element) Zeroize() {
// Zeroizing in 2 seperated loops tells compiler to
// use fast runtime.memclr()
for i := range fp.A {
fp.A[i] = 0
}
for i := range fp.B {
fp.B[i] = 0
}
}

View File

@ -1,140 +0,0 @@
package internal
const (
FP_MAX_WORDS = 12 // Currently p751.NumWords
)
// Representation of an element of the base field F_p.
//
// No particular meaning is assigned to the representation -- it could represent
// an element in Montgomery form, or not. Tracking the meaning of the field
// element is left to higher types.
type FpElement [FP_MAX_WORDS]uint64
// Represents an intermediate product of two elements of the base field F_p.
type FpElementX2 [2 * FP_MAX_WORDS]uint64
// Represents an element of the extended field Fp^2 = Fp(x+i)
type Fp2Element struct {
A FpElement
B FpElement
}
type DomainParams struct {
// P, Q and R=P-Q base points
Affine_P, Affine_Q, Affine_R Fp2Element
// Size of a compuatation strategy for x-torsion group
IsogenyStrategy []uint32
// Max size of secret key for x-torsion group
SecretBitLen uint
// Max size of secret key for x-torsion group
SecretByteLen uint
}
type SidhParams struct {
Id uint8
// Bytelen of P
Bytelen int
// The public key size, in bytes.
PublicKeySize int
// The shared secret size, in bytes.
SharedSecretSize uint
// 2- and 3-torsion group parameter definitions
A, B DomainParams
// Precomputed identity element in the Fp2 in Montgomery domain
OneFp2 Fp2Element
// Precomputed 1/2 in the Fp2 in Montgomery domain
HalfFp2 Fp2Element
// Length of SIKE secret message. Must be one of {24,32,40},
// depending on size of prime field used (see [SIKE], 1.4 and 5.1)
MsgLen uint
// Length of SIKE ephemeral KEM key (see [SIKE], 1.4 and 5.1)
KemSize uint
// Access to field arithmetic
Op FieldOps
}
// Interface for working with isogenies.
type Isogeny interface {
// Given a torsion point on a curve computes isogenous curve.
// Returns curve coefficients (A:C), so that E_(A/C) = E_(A/C)/<P>,
// where P is a provided projective point. Sets also isogeny constants
// that are needed for isogeny evaluation.
GenerateCurve(*ProjectivePoint) CurveCoefficientsEquiv
// Evaluates isogeny at caller provided point. Requires isogeny curve constants
// to be earlier computed by GenerateCurve.
EvaluatePoint(*ProjectivePoint) ProjectivePoint
}
// Stores curve projective parameters equivalent to A/C. Meaning of the
// values depends on the context. When working with isogenies over
// subgroup that are powers of:
// * three then (A:C) ~ (A+2C:A-2C)
// * four then (A:C) ~ (A+2C: 4C)
// See Appendix A of SIKE for more details
type CurveCoefficientsEquiv struct {
A Fp2Element
C Fp2Element
}
// A point on the projective line P^1(F_{p^2}).
//
// This represents a point on the Kummer line of a Montgomery curve. The
// curve is specified by a ProjectiveCurveParameters struct.
type ProjectivePoint struct {
X Fp2Element
Z Fp2Element
}
// A point on the projective line P^1(F_{p^2}).
//
// This is used to work projectively with the curve coefficients.
type ProjectiveCurveParameters struct {
A Fp2Element
C Fp2Element
}
// Stores Isogeny 3 curve constants
type isogeny3 struct {
Field FieldOps
K1 Fp2Element
K2 Fp2Element
}
// Stores Isogeny 4 curve constants
type isogeny4 struct {
isogeny3
K3 Fp2Element
}
type FieldOps interface {
// Set res = lhs + rhs.
//
// Allowed to overlap lhs or rhs with res.
Add(res, lhs, rhs *Fp2Element)
// Set res = lhs - rhs.
//
// Allowed to overlap lhs or rhs with res.
Sub(res, lhs, rhs *Fp2Element)
// Set res = lhs * rhs.
//
// Allowed to overlap lhs or rhs with res.
Mul(res, lhs, rhs *Fp2Element)
// Set res = x * x
//
// Allowed to overlap res with x.
Square(res, x *Fp2Element)
// Set res = 1/x
//
// Allowed to overlap res with x.
Inv(res, x *Fp2Element)
// If choice = 1u8, set (x,y) = (y,x). If choice = 0u8, set (x,y) = (x,y).
CondSwap(xPx, xPz, xQx, xQz *Fp2Element, choice uint8)
// Converts Fp2Element to Montgomery domain (x*R mod p)
ToMontgomery(x *Fp2Element)
// Converts 'a' in montgomery domain to element from Fp2Element
// and stores it in 'x'
FromMontgomery(x *Fp2Element, a *Fp2Element)
}

View File

@ -1,11 +0,0 @@
package utils
type x86 struct {
// Signals support for MULX which is in BMI2
HasBMI2 bool
// Signals support for ADX
HasADX bool
}
var X86 x86

View File

@ -1,29 +0,0 @@
// +build amd64,!noasm
// Sets capabilities flags for x86 according to information received from
// CPUID. It was written in accordance with
// "Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 2A".
// https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html
package utils
// Performs CPUID and returns values of registers
// go:nosplit
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
// Returns true in case bit 'n' in 'bits' is set, otherwise false
func bitn(bits uint32, n uint8) bool {
return (bits>>n)&1 == 1
}
func init() {
// CPUID returns max possible input that can be requested
max, _, _, _ := cpuid(0, 0)
if max < 7 {
return
}
_, ebx, _, _ := cpuid(7, 0)
X86.HasBMI2 = bitn(ebx, 8)
X86.HasADX = bitn(ebx, 19)
}

View File

@ -1,13 +0,0 @@
// +build amd64,!noasm
#include "textflag.h"
TEXT ·cpuid(SB), NOSPLIT, $0-4
MOVL eaxArg+0(FP), AX
MOVL ecxArg+4(FP), CX
CPUID
MOVL AX, eax+8(FP)
MOVL BX, ebx+12(FP)
MOVL CX, ecx+16(FP)
MOVL DX, edx+20(FP)
RET

File diff suppressed because it is too large Load Diff

View File

@ -1,802 +0,0 @@
// +build arm64,!noasm
#include "textflag.h"
TEXT ·fp503ConditionalSwap(SB), NOSPLIT, $0-17
MOVD x+0(FP), R0
MOVD y+8(FP), R1
MOVB choice+16(FP), R2
// Set flags
// If choice is not 0 or 1, this implementation will swap completely
CMP $0, R2
LDP 0(R0), (R3, R4)
LDP 0(R1), (R5, R6)
CSEL EQ, R3, R5, R7
CSEL EQ, R4, R6, R8
STP (R7, R8), 0(R0)
CSEL NE, R3, R5, R9
CSEL NE, R4, R6, R10
STP (R9, R10), 0(R1)
LDP 16(R0), (R3, R4)
LDP 16(R1), (R5, R6)
CSEL EQ, R3, R5, R7
CSEL EQ, R4, R6, R8
STP (R7, R8), 16(R0)
CSEL NE, R3, R5, R9
CSEL NE, R4, R6, R10
STP (R9, R10), 16(R1)
LDP 32(R0), (R3, R4)
LDP 32(R1), (R5, R6)
CSEL EQ, R3, R5, R7
CSEL EQ, R4, R6, R8
STP (R7, R8), 32(R0)
CSEL NE, R3, R5, R9
CSEL NE, R4, R6, R10
STP (R9, R10), 32(R1)
LDP 48(R0), (R3, R4)
LDP 48(R1), (R5, R6)
CSEL EQ, R3, R5, R7
CSEL EQ, R4, R6, R8
STP (R7, R8), 48(R0)
CSEL NE, R3, R5, R9
CSEL NE, R4, R6, R10
STP (R9, R10), 48(R1)
RET
TEXT ·fp503AddReduced(SB), NOSPLIT, $0-24
MOVD z+0(FP), R2
MOVD x+8(FP), R0
MOVD y+16(FP), R1
// Load first summand into R3-R10
// Add first summand and second summand and store result in R3-R10
LDP 0(R0), (R3, R4)
LDP 0(R1), (R11, R12)
LDP 16(R0), (R5, R6)
LDP 16(R1), (R13, R14)
ADDS R11, R3
ADCS R12, R4
ADCS R13, R5
ADCS R14, R6
LDP 32(R0), (R7, R8)
LDP 32(R1), (R11, R12)
LDP 48(R0), (R9, R10)
LDP 48(R1), (R13, R14)
ADCS R11, R7
ADCS R12, R8
ADCS R13, R9
ADC R14, R10
// Subtract 2 * p503 in R11-R17 from the result in R3-R10
LDP ·p503x2+0(SB), (R11, R12)
LDP ·p503x2+24(SB), (R13, R14)
SUBS R11, R3
SBCS R12, R4
LDP ·p503x2+40(SB), (R15, R16)
SBCS R12, R5
SBCS R13, R6
MOVD ·p503x2+56(SB), R17
SBCS R14, R7
SBCS R15, R8
SBCS R16, R9
SBCS R17, R10
SBC ZR, ZR, R19
// If x + y - 2 * p503 < 0, R19 is 1 and 2 * p503 should be added
AND R19, R11
AND R19, R12
AND R19, R13
AND R19, R14
AND R19, R15
AND R19, R16
AND R19, R17
ADDS R11, R3
ADCS R12, R4
STP (R3, R4), 0(R2)
ADCS R12, R5
ADCS R13, R6
STP (R5, R6), 16(R2)
ADCS R14, R7
ADCS R15, R8
STP (R7, R8), 32(R2)
ADCS R16, R9
ADC R17, R10
STP (R9, R10), 48(R2)
RET
TEXT ·fp503SubReduced(SB), NOSPLIT, $0-24
MOVD z+0(FP), R2
MOVD x+8(FP), R0
MOVD y+16(FP), R1
// Load x into R3-R10
// Subtract y from x and store result in R3-R10
LDP 0(R0), (R3, R4)
LDP 0(R1), (R11, R12)
LDP 16(R0), (R5, R6)
LDP 16(R1), (R13, R14)
SUBS R11, R3
SBCS R12, R4
SBCS R13, R5
SBCS R14, R6
LDP 32(R0), (R7, R8)
LDP 32(R1), (R11, R12)
LDP 48(R0), (R9, R10)
LDP 48(R1), (R13, R14)
SBCS R11, R7
SBCS R12, R8
SBCS R13, R9
SBCS R14, R10
SBC ZR, ZR, R19
// If x - y < 0, R19 is 1 and 2 * p503 should be added
LDP ·p503x2+0(SB), (R11, R12)
LDP ·p503x2+24(SB), (R13, R14)
AND R19, R11
AND R19, R12
LDP ·p503x2+40(SB), (R15, R16)
AND R19, R13
AND R19, R14
MOVD ·p503x2+56(SB), R17
AND R19, R15
AND R19, R16
AND R19, R17
ADDS R11, R3
ADCS R12, R4
STP (R3, R4), 0(R2)
ADCS R12, R5
ADCS R13, R6
STP (R5, R6), 16(R2)
ADCS R14, R7
ADCS R15, R8
STP (R7, R8), 32(R2)
ADCS R16, R9
ADC R17, R10
STP (R9, R10), 48(R2)
RET
TEXT ·fp503AddLazy(SB), NOSPLIT, $0-24
MOVD z+0(FP), R2
MOVD x+8(FP), R0
MOVD y+16(FP), R1
// Load first summand into R3-R10
// Add first summand and second summand and store result in R3-R10
LDP 0(R0), (R3, R4)
LDP 0(R1), (R11, R12)
LDP 16(R0), (R5, R6)
LDP 16(R1), (R13, R14)
ADDS R11, R3
ADCS R12, R4
STP (R3, R4), 0(R2)
ADCS R13, R5
ADCS R14, R6
STP (R5, R6), 16(R2)
LDP 32(R0), (R7, R8)
LDP 32(R1), (R11, R12)
LDP 48(R0), (R9, R10)
LDP 48(R1), (R13, R14)
ADCS R11, R7
ADCS R12, R8
STP (R7, R8), 32(R2)
ADCS R13, R9
ADC R14, R10
STP (R9, R10), 48(R2)
RET
TEXT ·fp503X2AddLazy(SB), NOSPLIT, $0-24
MOVD z+0(FP), R2
MOVD x+8(FP), R0
MOVD y+16(FP), R1
LDP 0(R0), (R3, R4)
LDP 0(R1), (R11, R12)
LDP 16(R0), (R5, R6)
LDP 16(R1), (R13, R14)
ADDS R11, R3
ADCS R12, R4
STP (R3, R4), 0(R2)
ADCS R13, R5
ADCS R14, R6
STP (R5, R6), 16(R2)
LDP 32(R0), (R7, R8)
LDP 32(R1), (R11, R12)
LDP 48(R0), (R9, R10)
LDP 48(R1), (R13, R14)
ADCS R11, R7
ADCS R12, R8
STP (R7, R8), 32(R2)
ADCS R13, R9
ADCS R14, R10
STP (R9, R10), 48(R2)
LDP 64(R0), (R3, R4)
LDP 64(R1), (R11, R12)
LDP 80(R0), (R5, R6)
LDP 80(R1), (R13, R14)
ADCS R11, R3
ADCS R12, R4
STP (R3, R4), 64(R2)
ADCS R13, R5
ADCS R14, R6
STP (R5, R6), 80(R2)
LDP 96(R0), (R7, R8)
LDP 96(R1), (R11, R12)
LDP 112(R0), (R9, R10)
LDP 112(R1), (R13, R14)
ADCS R11, R7
ADCS R12, R8
STP (R7, R8), 96(R2)
ADCS R13, R9
ADC R14, R10
STP (R9, R10), 112(R2)
RET
TEXT ·fp503X2SubLazy(SB), NOSPLIT, $0-24
MOVD z+0(FP), R2
MOVD x+8(FP), R0
MOVD y+16(FP), R1
LDP 0(R0), (R3, R4)
LDP 0(R1), (R11, R12)
LDP 16(R0), (R5, R6)
LDP 16(R1), (R13, R14)
SUBS R11, R3
SBCS R12, R4
STP (R3, R4), 0(R2)
SBCS R13, R5
SBCS R14, R6
STP (R5, R6), 16(R2)
LDP 32(R0), (R7, R8)
LDP 32(R1), (R11, R12)
LDP 48(R0), (R9, R10)
LDP 48(R1), (R13, R14)
SBCS R11, R7
SBCS R12, R8
STP (R7, R8), 32(R2)
SBCS R13, R9
SBCS R14, R10
STP (R9, R10), 48(R2)
LDP 64(R0), (R3, R4)
LDP 64(R1), (R11, R12)
LDP 80(R0), (R5, R6)
LDP 80(R1), (R13, R14)
SBCS R11, R3
SBCS R12, R4
SBCS R13, R5
SBCS R14, R6
LDP 96(R0), (R7, R8)
LDP 96(R1), (R11, R12)
LDP 112(R0), (R9, R10)
LDP 112(R1), (R13, R14)
SBCS R11, R7
SBCS R12, R8
SBCS R13, R9
SBCS R14, R10
SBC ZR, ZR, R15
// If x - y < 0, R15 is 1 and p503 should be added
LDP ·p503+16(SB), (R16, R17)
LDP ·p503+32(SB), (R19, R20)
AND R15, R16
AND R15, R17
LDP ·p503+48(SB), (R21, R22)
AND R15, R19
AND R15, R20
AND R15, R21
AND R15, R22
ADDS R16, R3
ADCS R16, R4
STP (R3, R4), 64(R2)
ADCS R16, R5
ADCS R17, R6
STP (R5, R6), 80(R2)
ADCS R19, R7
ADCS R20, R8
STP (R7, R8), 96(R2)
ADCS R21, R9
ADC R22, R10
STP (R9, R10), 112(R2)
RET
// Expects that X0*Y0 is already in Z0(low),Z3(high) and X0*Y1 in Z1(low),Z2(high)
// Z0 is not actually touched
// Result of (X0-X1) * (Y0-Y1) will be in Z0-Z3
// Inputs get overwritten, except for X1
#define mul128x128comba(X0, X1, Y0, Y1, Z0, Z1, Z2, Z3, T0) \
MUL X1, Y0, X0 \
UMULH X1, Y0, Y0 \
ADDS Z3, Z1 \
ADC ZR, Z2 \
\
MUL Y1, X1, T0 \
UMULH Y1, X1, Y1 \
ADDS X0, Z1 \
ADCS Y0, Z2 \
ADC ZR, ZR, Z3 \
\
ADDS T0, Z2 \
ADC Y1, Z3
// Expects that X points to (X0-X1)
// Result of (X0-X3) * (Y0-Y3) will be in Z0-Z7
// Inputs get overwritten, except X2-X3 and Y2-Y3
#define mul256x256karatsuba(X, X0, X1, X2, X3, Y0, Y1, Y2, Y3, Z0, Z1, Z2, Z3, Z4, Z5, Z6, Z7, T0, T1)\
ADDS X2, X0 \ // xH + xL, destroys xL
ADCS X3, X1 \
ADCS ZR, ZR, T0 \
\
ADDS Y2, Y0, Z6 \ // yH + yL
ADCS Y3, Y1, T1 \
ADC ZR, ZR, Z7 \
\
SUB T0, ZR, Z2 \
SUB Z7, ZR, Z3 \
AND Z7, T0 \ // combined carry
\
AND Z2, Z6, Z0 \ // masked(yH + yL)
AND Z2, T1, Z1 \
\
AND Z3, X0, Z4 \ // masked(xH + xL)
AND Z3, X1, Z5 \
\
MUL Z6, X0, Z2 \
MUL T1, X0, Z3 \
\
ADDS Z4, Z0 \
UMULH T1, X0, Z4 \
ADCS Z5, Z1 \
UMULH Z6, X0, Z5 \
ADC ZR, T0 \
\ // (xH + xL) * (yH + yL)
mul128x128comba(X0, X1, Z6, T1, Z2, Z3, Z4, Z5, Z7)\
\
LDP 0+X, (X0, X1) \
\
ADDS Z0, Z4 \
UMULH Y0, X0, Z7 \
UMULH Y1, X0, T1 \
ADCS Z1, Z5 \
MUL Y0, X0, Z0 \
MUL Y1, X0, Z1 \
ADC ZR, T0 \
\ // xL * yL
mul128x128comba(X0, X1, Y0, Y1, Z0, Z1, T1, Z7, Z6)\
\
MUL Y2, X2, X0 \
UMULH Y2, X2, Y0 \
SUBS Z0, Z2 \ // (xH + xL) * (yH + yL) - xL * yL
SBCS Z1, Z3 \
SBCS T1, Z4 \
MUL Y3, X2, X1 \
UMULH Y3, X2, Z6 \
SBCS Z7, Z5 \
SBCS ZR, T0 \
\ // xH * yH
mul128x128comba(X2, X3, Y2, Y3, X0, X1, Z6, Y0, Y1)\
\
SUBS X0, Z2 \ // (xH + xL) * (yH + yL) - xL * yL - xH * yH
SBCS X1, Z3 \
SBCS Z6, Z4 \
SBCS Y0, Z5 \
SBCS ZR, T0 \
\
ADDS T1, Z2 \ // (xH * yH) * 2^256 + ((xH + xL) * (yH + yL) - xL * yL - xH * yH) * 2^128 + xL * yL
ADCS Z7, Z3 \
ADCS X0, Z4 \
ADCS X1, Z5 \
ADCS T0, Z6 \
ADC Y0, ZR, Z7
// This implements two-level Karatsuba with a 128x128 Comba multiplier
// at the bottom
TEXT ·fp503Mul(SB), NOSPLIT, $0-24
MOVD z+0(FP), R2
MOVD x+8(FP), R0
MOVD y+16(FP), R1
// Load xL in R3-R6, xH in R7-R10
// (xH + xL) in R25-R29
LDP 0(R0), (R3, R4)
LDP 32(R0), (R7, R8)
ADDS R3, R7, R25
ADCS R4, R8, R26
LDP 16(R0), (R5, R6)
LDP 48(R0), (R9, R10)
ADCS R5, R9, R27
ADCS R6, R10, R29
ADC ZR, ZR, R7
// Load yL in R11-R14, yH in R15-19
// (yH + yL) in R11-R14, destroys yL
LDP 0(R1), (R11, R12)
LDP 32(R1), (R15, R16)
ADDS R15, R11
ADCS R16, R12
LDP 16(R1), (R13, R14)
LDP 48(R1), (R17, R19)
ADCS R17, R13
ADCS R19, R14
ADC ZR, ZR, R8
// Compute maskes and combined carry
SUB R7, ZR, R9
SUB R8, ZR, R10
AND R8, R7
// masked(yH + yL)
AND R9, R11, R15
AND R9, R12, R16
AND R9, R13, R17
AND R9, R14, R19
// masked(xH + xL)
AND R10, R25, R20
AND R10, R26, R21
AND R10, R27, R22
AND R10, R29, R23
// masked(xH + xL) + masked(yH + yL) in R15-R19
ADDS R20, R15
ADCS R21, R16
ADCS R22, R17
ADCS R23, R19
ADC ZR, R7
// Use z as temporary storage
STP (R25, R26), 0(R2)
// (xH + xL) * (yH + yL)
mul256x256karatsuba(0(R2), R25, R26, R27, R29, R11, R12, R13, R14, R8, R9, R10, R20, R21, R22, R23, R24, R0, R1)
MOVD x+8(FP), R0
MOVD y+16(FP), R1
ADDS R21, R15
ADCS R22, R16
ADCS R23, R17
ADCS R24, R19
ADC ZR, R7
// Load yL in R11-R14
LDP 0(R1), (R11, R12)
LDP 16(R1), (R13, R14)
// xL * yL
mul256x256karatsuba(0(R0), R3, R4, R5, R6, R11, R12, R13, R14, R21, R22, R23, R24, R25, R26, R27, R29, R1, R2)
MOVD z+0(FP), R2
MOVD y+16(FP), R1
// (xH + xL) * (yH + yL) - xL * yL
SUBS R21, R8
SBCS R22, R9
STP (R21, R22), 0(R2)
SBCS R23, R10
SBCS R24, R20
STP (R23, R24), 16(R2)
SBCS R25, R15
SBCS R26, R16
SBCS R27, R17
SBCS R29, R19
SBC ZR, R7
// Load xH in R3-R6, yH in R11-R14
LDP 32(R0), (R3, R4)
LDP 48(R0), (R5, R6)
LDP 32(R1), (R11, R12)
LDP 48(R1), (R13, R14)
ADDS R25, R8
ADCS R26, R9
ADCS R27, R10
ADCS R29, R20
ADC ZR, ZR, R1
MOVD R20, 32(R2)
// xH * yH
mul256x256karatsuba(32(R0), R3, R4, R5, R6, R11, R12, R13, R14, R21, R22, R23, R24, R25, R26, R27, R29, R2, R20)
NEG R1, R1
MOVD z+0(FP), R2
MOVD 32(R2), R20
// (xH + xL) * (yH + yL) - xL * yL - xH * yH in R8-R10,R20,R15-R19
// Store lower half in z, that's done
SUBS R21, R8
SBCS R22, R9
STP (R8, R9), 32(R2)
SBCS R23, R10
SBCS R24, R20
STP (R10, R20), 48(R2)
SBCS R25, R15
SBCS R26, R16
SBCS R27, R17
SBCS R29, R19
SBC ZR, R7
// (xH * yH) * 2^512 + ((xH + xL) * (yH + yL) - xL * yL - xH * yH) * 2^256 + xL * yL
// Store remaining limbs in z
ADDS $1, R1
ADCS R21, R15
ADCS R22, R16
STP (R15, R16), 64(R2)
ADCS R23, R17
ADCS R24, R19
STP (R17, R19), 80(R2)
ADCS R7, R25
ADCS ZR, R26
STP (R25, R26), 96(R2)
ADCS ZR, R27
ADC ZR, R29
STP (R27, R29), 112(R2)
RET
// Expects that X0*Y0 is already in Z0(low),Z3(high) and X0*Y1 in Z1(low),Z2(high)
// Z0 is not actually touched
// Result of (X0-X1) * (Y0-Y3) will be in Z0-Z5
// Inputs remain intact
#define mul128x256comba(X0, X1, Y0, Y1, Y2, Y3, Z0, Z1, Z2, Z3, Z4, Z5, T0, T1, T2, T3)\
MUL X1, Y0, T0 \
UMULH X1, Y0, T1 \
ADDS Z3, Z1 \
ADC ZR, Z2 \
\
MUL X0, Y2, T2 \
UMULH X0, Y2, T3 \
ADDS T0, Z1 \
ADCS T1, Z2 \
ADC ZR, ZR, Z3 \
\
MUL X1, Y1, T0 \
UMULH X1, Y1, T1 \
ADDS T2, Z2 \
ADCS T3, Z3 \
ADC ZR, ZR, Z4 \
\
MUL X0, Y3, T2 \
UMULH X0, Y3, T3 \
ADDS T0, Z2 \
ADCS T1, Z3 \
ADC ZR, Z4 \
\
MUL X1, Y2, T0 \
UMULH X1, Y2, T1 \
ADDS T2, Z3 \
ADCS T3, Z4 \
ADC ZR, ZR, Z5 \
\
MUL X1, Y3, T2 \
UMULH X1, Y3, T3 \
ADDS T0, Z3 \
ADCS T1, Z4 \
ADC ZR, Z5 \
ADDS T2, Z4 \
ADC T3, Z5
// This implements the shifted 2^(B*w) Montgomery reduction from
// https://eprint.iacr.org/2016/986.pdf, section Section 3.2, with
// B = 4, w = 64. Performance results were reported in
// https://eprint.iacr.org/2018/700.pdf Section 6.
TEXT ·fp503MontgomeryReduce(SB), NOSPLIT, $0-16
MOVD x+8(FP), R0
// Load x0-x1
LDP 0(R0), (R2, R3)
// Load the prime constant in R25-R29
LDP ·p503p1s8+32(SB), (R25, R26)
LDP ·p503p1s8+48(SB), (R27, R29)
// [x0,x1] * p503p1s8 to R4-R9
MUL R2, R25, R4 // x0 * p503p1s8[0]
UMULH R2, R25, R7
MUL R2, R26, R5 // x0 * p503p1s8[1]
UMULH R2, R26, R6
mul128x256comba(R2, R3, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13)
LDP 16(R0), (R3, R11) // x2
LDP 32(R0), (R12, R13)
LDP 48(R0), (R14, R15)
// Left-shift result in R4-R9 by 56 to R4-R10
ORR R9>>8, ZR, R10
LSL $56, R9
ORR R8>>8, R9
LSL $56, R8
ORR R7>>8, R8
LSL $56, R7
ORR R6>>8, R7
LSL $56, R6
ORR R5>>8, R6
LSL $56, R5
ORR R4>>8, R5
LSL $56, R4
ADDS R4, R11 // x3
ADCS R5, R12 // x4
ADCS R6, R13
ADCS R7, R14
ADCS R8, R15
LDP 64(R0), (R16, R17)
LDP 80(R0), (R19, R20)
MUL R3, R25, R4 // x2 * p503p1s8[0]
UMULH R3, R25, R7
ADCS R9, R16
ADCS R10, R17
ADCS ZR, R19
ADCS ZR, R20
LDP 96(R0), (R21, R22)
LDP 112(R0), (R23, R24)
MUL R3, R26, R5 // x2 * p503p1s8[1]
UMULH R3, R26, R6
ADCS ZR, R21
ADCS ZR, R22
ADCS ZR, R23
ADC ZR, R24
// [x2,x3] * p503p1s8 to R4-R9
mul128x256comba(R3, R11, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R0, R1, R2)
ORR R9>>8, ZR, R10
LSL $56, R9
ORR R8>>8, R9
LSL $56, R8
ORR R7>>8, R8
LSL $56, R7
ORR R6>>8, R7
LSL $56, R6
ORR R5>>8, R6
LSL $56, R5
ORR R4>>8, R5
LSL $56, R4
ADDS R4, R13 // x5
ADCS R5, R14 // x6
ADCS R6, R15
ADCS R7, R16
MUL R12, R25, R4 // x4 * p503p1s8[0]
UMULH R12, R25, R7
ADCS R8, R17
ADCS R9, R19
ADCS R10, R20
ADCS ZR, R21
MUL R12, R26, R5 // x4 * p503p1s8[1]
UMULH R12, R26, R6
ADCS ZR, R22
ADCS ZR, R23
ADC ZR, R24
// [x4,x5] * p503p1s8 to R4-R9
mul128x256comba(R12, R13, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R0, R1, R2)
ORR R9>>8, ZR, R10
LSL $56, R9
ORR R8>>8, R9
LSL $56, R8
ORR R7>>8, R8
LSL $56, R7
ORR R6>>8, R7
LSL $56, R6
ORR R5>>8, R6
LSL $56, R5
ORR R4>>8, R5
LSL $56, R4
ADDS R4, R15 // x7
ADCS R5, R16 // x8
ADCS R6, R17
ADCS R7, R19
MUL R14, R25, R4 // x6 * p503p1s8[0]
UMULH R14, R25, R7
ADCS R8, R20
ADCS R9, R21
ADCS R10, R22
MUL R14, R26, R5 // x6 * p503p1s8[1]
UMULH R14, R26, R6
ADCS ZR, R23
ADC ZR, R24
// [x6,x7] * p503p1s8 to R4-R9
mul128x256comba(R14, R15, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R0, R1, R2)
ORR R9>>8, ZR, R10
LSL $56, R9
ORR R8>>8, R9
LSL $56, R8
ORR R7>>8, R8
LSL $56, R7
ORR R6>>8, R7
LSL $56, R6
ORR R5>>8, R6
LSL $56, R5
ORR R4>>8, R5
LSL $56, R4
MOVD z+0(FP), R0
ADDS R4, R17
ADCS R5, R19
STP (R16, R17), 0(R0) // Store final result to z
ADCS R6, R20
ADCS R7, R21
STP (R19, R20), 16(R0)
ADCS R8, R22
ADCS R9, R23
STP (R21, R22), 32(R0)
ADC R10, R24
STP (R23, R24), 48(R0)
RET
TEXT ·fp503StrongReduce(SB), NOSPLIT, $0-8
MOVD x+0(FP), R0
// Keep x in R1-R8, p503 in R9-R14, subtract to R1-R8
LDP ·p503+16(SB), (R9, R10)
LDP 0(R0), (R1, R2)
LDP 16(R0), (R3, R4)
SUBS R9, R1
SBCS R9, R2
LDP 32(R0), (R5, R6)
LDP ·p503+32(SB), (R11, R12)
SBCS R9, R3
SBCS R10, R4
LDP 48(R0), (R7, R8)
LDP ·p503+48(SB), (R13, R14)
SBCS R11, R5
SBCS R12, R6
SBCS R13, R7
SBCS R14, R8
SBC ZR, ZR, R15
// Mask with the borrow and add p503
AND R15, R9
AND R15, R10
AND R15, R11
AND R15, R12
AND R15, R13
AND R15, R14
ADDS R9, R1
ADCS R9, R2
STP (R1, R2), 0(R0)
ADCS R9, R3
ADCS R10, R4
STP (R3, R4), 16(R0)
ADCS R11, R5
ADCS R12, R6
STP (R5, R6), 32(R0)
ADCS R13, R7
ADCS R14, R8
STP (R7, R8), 48(R0)
RET

View File

@ -1,46 +0,0 @@
// +build amd64,!noasm arm64,!noasm
package p503
import (
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
)
// If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x.
// If choice is neither 0 nor 1 then behaviour is undefined.
// This function executes in constant time.
//go:noescape
func fp503ConditionalSwap(x, y *FpElement, choice uint8)
// Compute z = x + y (mod p).
//go:noescape
func fp503AddReduced(z, x, y *FpElement)
// Compute z = x - y (mod p).
//go:noescape
func fp503SubReduced(z, x, y *FpElement)
// Compute z = x + y, without reducing mod p.
//go:noescape
func fp503AddLazy(z, x, y *FpElement)
// Compute z = x + y, without reducing mod p.
//go:noescape
func fp503X2AddLazy(z, x, y *FpElementX2)
// Compute z = x - y, without reducing mod p.
//go:noescape
func fp503X2SubLazy(z, x, y *FpElementX2)
// Reduce a field element in [0, 2*p) to one in [0,p).
//go:noescape
func fp503StrongReduce(x *FpElement)
// Computes z = x * y.
//go:noescape
func fp503Mul(z *FpElementX2, x, y *FpElement)
// Computes the Montgomery reduction z = x R^{-1} (mod 2*p). On return value
// of x may be changed. z=x not allowed.
//go:noescape
func fp503MontgomeryReduce(z *FpElement, x *FpElementX2)

View File

@ -1,197 +0,0 @@
// +build noasm !amd64,!arm64
package p503
import (
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/arith"
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
)
// Compute z = x + y (mod p).
func fp503AddReduced(z, x, y *FpElement) {
var carry uint64
// z=x+y % p503
for i := 0; i < NumWords; i++ {
z[i], carry = Addc64(carry, x[i], y[i])
}
// z = z - p503x2
carry = 0
for i := 0; i < NumWords; i++ {
z[i], carry = Subc64(carry, z[i], p503x2[i])
}
// if z<0 add p503x2 back
mask := uint64(0 - carry)
carry = 0
for i := 0; i < NumWords; i++ {
z[i], carry = Addc64(carry, z[i], p503x2[i]&mask)
}
}
// Compute z = x - y (mod p).
func fp503SubReduced(z, x, y *FpElement) {
var borrow uint64
// z = z - p503x2
for i := 0; i < NumWords; i++ {
z[i], borrow = Subc64(borrow, x[i], y[i])
}
// if z<0 add p503x2 back
mask := uint64(0 - borrow)
borrow = 0
for i := 0; i < NumWords; i++ {
z[i], borrow = Addc64(borrow, z[i], p503x2[i]&mask)
}
}
// Conditionally swaps bits in x and y in constant time.
// mask indicates bits to be swapped (set bits are swapped)
// For details see "Hackers Delight, 2.20"
//
// Implementation doesn't actually depend on a prime field.
func fp503ConditionalSwap(x, y *FpElement, mask uint8) {
var tmp, mask64 uint64
mask64 = 0 - uint64(mask)
for i := 0; i < NumWords; i++ {
tmp = mask64 & (x[i] ^ y[i])
x[i] = tmp ^ x[i]
y[i] = tmp ^ y[i]
}
}
// Perform Montgomery reduction: set z = x R^{-1} (mod 2*p)
// with R=2^512. Destroys the input value.
func fp503MontgomeryReduce(z *FpElement, x *FpElementX2) {
var carry, t, u, v uint64
var uv Uint128
var count int
count = 3 // number of 0 digits in the least significat part of p503 + 1
for i := 0; i < NumWords; i++ {
for j := 0; j < i; j++ {
if j < (i - count + 1) {
uv = Mul64(z[j], p503p1[i-j])
v, carry = Addc64(0, uv.L, v)
u, carry = Addc64(carry, uv.H, u)
t += carry
}
}
v, carry = Addc64(0, v, x[i])
u, carry = Addc64(carry, u, 0)
t += carry
z[i] = v
v = u
u = t
t = 0
}
for i := NumWords; i < 2*NumWords-1; i++ {
if count > 0 {
count--
}
for j := i - NumWords + 1; j < NumWords; j++ {
if j < (NumWords - count) {
uv = Mul64(z[j], p503p1[i-j])
v, carry = Addc64(0, uv.L, v)
u, carry = Addc64(carry, uv.H, u)
t += carry
}
}
v, carry = Addc64(0, v, x[i])
u, carry = Addc64(carry, u, 0)
t += carry
z[i-NumWords] = v
v = u
u = t
t = 0
}
v, carry = Addc64(0, v, x[2*NumWords-1])
z[NumWords-1] = v
}
// Compute z = x * y.
func fp503Mul(z *FpElementX2, x, y *FpElement) {
var u, v, t uint64
var carry uint64
var uv Uint128
for i := uint64(0); i < NumWords; i++ {
for j := uint64(0); j <= i; j++ {
uv = Mul64(x[j], y[i-j])
v, carry = Addc64(0, uv.L, v)
u, carry = Addc64(carry, uv.H, u)
t += carry
}
z[i] = v
v = u
u = t
t = 0
}
for i := NumWords; i < (2*NumWords)-1; i++ {
for j := i - NumWords + 1; j < NumWords; j++ {
uv = Mul64(x[j], y[i-j])
v, carry = Addc64(0, uv.L, v)
u, carry = Addc64(carry, uv.H, u)
t += carry
}
z[i] = v
v = u
u = t
t = 0
}
z[2*NumWords-1] = v
}
// Compute z = x + y, without reducing mod p.
func fp503AddLazy(z, x, y *FpElement) {
var carry uint64
for i := 0; i < NumWords; i++ {
z[i], carry = Addc64(carry, x[i], y[i])
}
}
// Compute z = x + y, without reducing mod p.
func fp503X2AddLazy(z, x, y *FpElementX2) {
var carry uint64
for i := 0; i < 2*NumWords; i++ {
z[i], carry = Addc64(carry, x[i], y[i])
}
}
// Reduce a field element in [0, 2*p) to one in [0,p).
func fp503StrongReduce(x *FpElement) {
var borrow, mask uint64
for i := 0; i < NumWords; i++ {
x[i], borrow = Subc64(borrow, x[i], p503[i])
}
// Sets all bits if borrow = 1
mask = 0 - borrow
borrow = 0
for i := 0; i < NumWords; i++ {
x[i], borrow = Addc64(borrow, x[i], p503[i]&mask)
}
}
// Compute z = x - y, without reducing mod p.
func fp503X2SubLazy(z, x, y *FpElementX2) {
var borrow, mask uint64
for i := 0; i < 2*NumWords; i++ {
z[i], borrow = Subc64(borrow, x[i], y[i])
}
// Sets all bits if borrow = 1
mask = 0 - borrow
borrow = 0
for i := NumWords; i < 2*NumWords; i++ {
z[i], borrow = Addc64(borrow, z[i], p503[i-NumWords]&mask)
}
}

View File

@ -1,178 +0,0 @@
package p503
import (
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
cpu "v2ray.com/core/external/github.com/cloudflare/sidh/internal/utils"
)
const (
// SIDH public key byte size
P503_PublicKeySize = 378
// SIDH shared secret byte size.
P503_SharedSecretSize = 126
// Max size of secret key for 2-torsion group, corresponds to 2^e2 - 1
P503_SecretBitLenA = 250
// Size of secret key for 3-torsion group, corresponds to log_2(3^e3) - 1
P503_SecretBitLenB = 252
// Size of a compuatation strategy for 2-torsion group
strategySizeA = 124
// Size of a compuatation strategy for 3-torsion group
strategySizeB = 158
// ceil(503+7/8)
P503_Bytelen = 63
// Number of limbs for a field element
NumWords = 8
)
// CPU Capabilities. Those flags are referred by assembly code. According to
// https://github.com/golang/go/issues/28230, variables referred from the
// assembly must be in the same package.
// We declare them variables not constants in order to facilitate testing.
var (
// Signals support for MULX which is in BMI2
HasBMI2 = cpu.X86.HasBMI2
// Signals support for ADX and BMI2
HasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX
)
// The x-coordinate of PA
var P503_affine_PA = Fp2Element{
A: FpElement{
0xE7EF4AA786D855AF, 0xED5758F03EB34D3B, 0x09AE172535A86AA9, 0x237B9CC07D622723,
0xE3A284CBA4E7932D, 0x27481D9176C5E63F, 0x6A323FF55C6E71BF, 0x002ECC31A6FB8773,
},
B: FpElement{
0x64D02E4E90A620B8, 0xDAB8128537D4B9F1, 0x4BADF77B8A228F98, 0x0F5DBDF9D1FB7D1B,
0xBEC4DB288E1A0DCC, 0xE76A8665E80675DB, 0x6D6F252E12929463, 0x003188BD1463FACC,
},
}
// The x-coordinate of QA
var P503_affine_QA = Fp2Element{
A: FpElement{
0xB79D41025DE85D56, 0x0B867DA9DF169686, 0x740E5368021C827D, 0x20615D72157BF25C,
0xFF1590013C9B9F5B, 0xC884DCADE8C16CEA, 0xEBD05E53BF724E01, 0x0032FEF8FDA5748C,
},
B: FpElement{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
},
}
// The x-coordinate of RA = PA-QA
var P503_affine_RA = Fp2Element{
A: FpElement{
0x12E2E849AA0A8006, 0x41CF47008635A1E8, 0x9CD720A70798AED7, 0x42A820B42FCF04CF,
0x7BF9BAD32AAE88B1, 0xF619127A54090BBE, 0x1CB10D8F56408EAA, 0x001D6B54C3C0EDEB,
},
B: FpElement{
0x34DB54931CBAAC36, 0x420A18CB8DD5F0C4, 0x32008C1A48C0F44D, 0x3B3BA772B1CFD44D,
0xA74B058FDAF13515, 0x095FC9CA7EEC17B4, 0x448E829D28F120F8, 0x00261EC3ED16A489,
},
}
// The x-coordinate of PB
var P503_affine_PB = Fp2Element{
A: FpElement{
0x7EDE37F4FA0BC727, 0xF7F8EC5C8598941C, 0xD15519B516B5F5C8, 0xF6D5AC9B87A36282,
0x7B19F105B30E952E, 0x13BD8B2025B4EBEE, 0x7B96D27F4EC579A2, 0x00140850CAB7E5DE,
},
B: FpElement{
0x7764909DAE7B7B2D, 0x578ABB16284911AB, 0x76E2BFD146A6BF4D, 0x4824044B23AA02F0,
0x1105048912A321F3, 0xB8A2E482CF0F10C1, 0x42FF7D0BE2152085, 0x0018E599C5223352,
},
}
// The x-coordinate of QB
var P503_affine_QB = Fp2Element{
A: FpElement{
0x4256C520FB388820, 0x744FD7C3BAAF0A13, 0x4B6A2DDDB12CBCB8, 0xE46826E27F427DF8,
0xFE4A663CD505A61B, 0xD6B3A1BAF025C695, 0x7C3BB62B8FCC00BD, 0x003AFDDE4A35746C,
},
B: FpElement{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
},
}
// The x-coordinate of RB = PB - QB
var P503_affine_RB = Fp2Element{
A: FpElement{
0x75601CD1E6C0DFCB, 0x1A9007239B58F93E, 0xC1F1BE80C62107AC, 0x7F513B898F29FF08,
0xEA0BEDFF43E1F7B2, 0x2C6D94018CBAE6D0, 0x3A430D31BCD84672, 0x000D26892ECCFE83,
},
B: FpElement{
0x1119D62AEA3007A1, 0xE3702AA4E04BAE1B, 0x9AB96F7D59F990E7, 0xF58440E8B43319C0,
0xAF8134BEE1489775, 0xE7F7774E905192AA, 0xF54AE09308E98039, 0x001EF7A041A86112,
},
}
// 2-torsion group computation strategy
var P503_AliceIsogenyStrategy = [strategySizeA]uint32{
0x3D, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02,
0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
0x01, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x1D, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x0D, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x05, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01}
// 3-torsion group computation strategy
var P503_BobIsogenyStrategy = [strategySizeB]uint32{
0x47, 0x26, 0x15, 0x0D, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01,
0x02, 0x01, 0x01, 0x05, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09,
0x05, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x11, 0x09, 0x05, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01,
0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x21, 0x11, 0x09, 0x05, 0x03, 0x02, 0x01, 0x01,
0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04,
0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x10, 0x08,
0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08,
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}
// Used internally by this package
// -------------------------------
var p503 = FpElement{
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xABFFFFFFFFFFFFFF,
0x13085BDA2211E7A0, 0x1B9BF6C87B7E7DAF, 0x6045C6BDDA77A4D0, 0x004066F541811E1E,
}
// 2*503
var p503x2 = FpElement{
0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x57FFFFFFFFFFFFFF,
0x2610B7B44423CF41, 0x3737ED90F6FCFB5E, 0xC08B8D7BB4EF49A0, 0x0080CDEA83023C3C,
}
// p503 + 1
var p503p1 = FpElement{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xAC00000000000000,
0x13085BDA2211E7A0, 0x1B9BF6C87B7E7DAF, 0x6045C6BDDA77A4D0, 0x004066F541811E1E,
}
// R^2=(2^512)^2 mod p
var p503R2 = FpElement{
0x5289A0CF641D011F, 0x9B88257189FED2B9, 0xA3B365D58DC8F17A, 0x5BC57AB6EFF168EC,
0x9E51998BD84D4423, 0xBF8999CBAC3B5695, 0x46E9127BCE14CDB6, 0x003F6CFCE8B81771,
}
// p503 + 1 left-shifted by 8, assuming little endianness
var p503p1s8 = FpElement{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x085BDA2211E7A0AC, 0x9BF6C87B7E7DAF13, 0x45C6BDDA77A4D01B, 0x4066F541811E1E60,
}
// 1*R mod p
var P503_OneFp2 = Fp2Element{
A: FpElement{
0x00000000000003F9, 0x0000000000000000, 0x0000000000000000, 0xB400000000000000,
0x63CB1A6EA6DED2B4, 0x51689D8D667EB37D, 0x8ACD77C71AB24142, 0x0026FBAEC60F5953},
}
// 1/2 * R mod p
var P503_HalfFp2 = Fp2Element{
A: FpElement{
0x00000000000001FC, 0x0000000000000000, 0x0000000000000000, 0xB000000000000000,
0x3B69BB2464785D2A, 0x36824A2AF0FE9896, 0xF5899F427A94F309, 0x0033B15203C83BB8},
}

View File

@ -1,249 +0,0 @@
package p503
import (
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
)
type fp503Ops struct{}
func FieldOperations() FieldOps {
return &fp503Ops{}
}
func (fp503Ops) Add(dest, lhs, rhs *Fp2Element) {
fp503AddReduced(&dest.A, &lhs.A, &rhs.A)
fp503AddReduced(&dest.B, &lhs.B, &rhs.B)
}
func (fp503Ops) Sub(dest, lhs, rhs *Fp2Element) {
fp503SubReduced(&dest.A, &lhs.A, &rhs.A)
fp503SubReduced(&dest.B, &lhs.B, &rhs.B)
}
func (fp503Ops) Mul(dest, lhs, rhs *Fp2Element) {
// Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b).
a := &lhs.A
b := &lhs.B
c := &rhs.A
d := &rhs.B
// We want to compute
//
// (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i
//
// Use Karatsuba's trick: note that
//
// (b - a)*(c - d) = (b*c + a*d) - a*c - b*d
//
// so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d.
var ac, bd FpElementX2
fp503Mul(&ac, a, c) // = a*c*R*R
fp503Mul(&bd, b, d) // = b*d*R*R
var b_minus_a, c_minus_d FpElement
fp503SubReduced(&b_minus_a, b, a) // = (b-a)*R
fp503SubReduced(&c_minus_d, c, d) // = (c-d)*R
var ad_plus_bc FpElementX2
fp503Mul(&ad_plus_bc, &b_minus_a, &c_minus_d) // = (b-a)*(c-d)*R*R
fp503X2AddLazy(&ad_plus_bc, &ad_plus_bc, &ac) // = ((b-a)*(c-d) + a*c)*R*R
fp503X2AddLazy(&ad_plus_bc, &ad_plus_bc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R
fp503MontgomeryReduce(&dest.B, &ad_plus_bc) // = (a*d + b*c)*R mod p
var ac_minus_bd FpElementX2
fp503X2SubLazy(&ac_minus_bd, &ac, &bd) // = (a*c - b*d)*R*R
fp503MontgomeryReduce(&dest.A, &ac_minus_bd) // = (a*c - b*d)*R mod p
}
// Set dest = 1/x
//
// Allowed to overlap dest with x.
//
// Returns dest to allow chaining operations.
func (fp503Ops) Inv(dest, x *Fp2Element) {
a := &x.A
b := &x.B
// We want to compute
//
// 1 1 (a - bi) (a - bi)
// -------- = -------- -------- = -----------
// (a + bi) (a + bi) (a - bi) (a^2 + b^2)
//
// Letting c = 1/(a^2 + b^2), this is
//
// 1/(a+bi) = a*c - b*ci.
var asq_plus_bsq primeFieldElement
var asq, bsq FpElementX2
fp503Mul(&asq, a, a) // = a*a*R*R
fp503Mul(&bsq, b, b) // = b*b*R*R
fp503X2AddLazy(&asq, &asq, &bsq) // = (a^2 + b^2)*R*R
fp503MontgomeryReduce(&asq_plus_bsq.A, &asq) // = (a^2 + b^2)*R mod p
// Now asq_plus_bsq = a^2 + b^2
inv := asq_plus_bsq
inv.Mul(&asq_plus_bsq, &asq_plus_bsq)
inv.P34(&inv)
inv.Mul(&inv, &inv)
inv.Mul(&inv, &asq_plus_bsq)
var ac FpElementX2
fp503Mul(&ac, a, &inv.A)
fp503MontgomeryReduce(&dest.A, &ac)
var minus_b FpElement
fp503SubReduced(&minus_b, &minus_b, b)
var minus_bc FpElementX2
fp503Mul(&minus_bc, &minus_b, &inv.A)
fp503MontgomeryReduce(&dest.B, &minus_bc)
}
func (fp503Ops) Square(dest, x *Fp2Element) {
a := &x.A
b := &x.B
// We want to compute
//
// (a + bi)*(a + bi) = (a^2 - b^2) + 2abi.
var a2, a_plus_b, a_minus_b FpElement
fp503AddReduced(&a2, a, a) // = a*R + a*R = 2*a*R
fp503AddReduced(&a_plus_b, a, b) // = a*R + b*R = (a+b)*R
fp503SubReduced(&a_minus_b, a, b) // = a*R - b*R = (a-b)*R
var asq_minus_bsq, ab2 FpElementX2
fp503Mul(&asq_minus_bsq, &a_plus_b, &a_minus_b) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R
fp503Mul(&ab2, &a2, b) // = 2*a*b*R*R
fp503MontgomeryReduce(&dest.A, &asq_minus_bsq) // = (a^2 - b^2)*R mod p
fp503MontgomeryReduce(&dest.B, &ab2) // = 2*a*b*R mod p
}
// In case choice == 1, performs following swap in constant time:
// xPx <-> xQx
// xPz <-> xQz
// Otherwise returns xPx, xPz, xQx, xQz unchanged
func (fp503Ops) CondSwap(xPx, xPz, xQx, xQz *Fp2Element, choice uint8) {
fp503ConditionalSwap(&xPx.A, &xQx.A, choice)
fp503ConditionalSwap(&xPx.B, &xQx.B, choice)
fp503ConditionalSwap(&xPz.A, &xQz.A, choice)
fp503ConditionalSwap(&xPz.B, &xQz.B, choice)
}
// Converts values in x.A and x.B to Montgomery domain
// x.A = x.A * R mod p
// x.B = x.B * R mod p
// Performs v = v*R^2*R^(-1) mod p, for both x.A and x.B
func (fp503Ops) ToMontgomery(x *Fp2Element) {
var aRR FpElementX2
// convert to montgomery domain
fp503Mul(&aRR, &x.A, &p503R2) // = a*R*R
fp503MontgomeryReduce(&x.A, &aRR) // = a*R mod p
fp503Mul(&aRR, &x.B, &p503R2)
fp503MontgomeryReduce(&x.B, &aRR)
}
// Converts values in x.A and x.B from Montgomery domain
// a = x.A mod p
// b = x.B mod p
//
// After returning from the call x is not modified.
func (fp503Ops) FromMontgomery(x *Fp2Element, out *Fp2Element) {
var aR FpElementX2
// convert from montgomery domain
// TODO: make fpXXXMontgomeryReduce use stack instead of reusing aR
// so that we don't have do this copy here
copy(aR[:], x.A[:])
fp503MontgomeryReduce(&out.A, &aR) // = a mod p in [0, 2p)
fp503StrongReduce(&out.A) // = a mod p in [0, p)
for i := range aR {
aR[i] = 0
}
copy(aR[:], x.B[:])
fp503MontgomeryReduce(&out.B, &aR)
fp503StrongReduce(&out.B)
}
//------------------------------------------------------------------------------
// Prime Field
//------------------------------------------------------------------------------
// Represents an element of the prime field F_p.
type primeFieldElement struct {
// This field element is in Montgomery form, so that the value `A` is
// represented by `aR mod p`.
A FpElement
}
// Set dest = lhs * rhs.
//
// Allowed to overlap lhs or rhs with dest.
//
// Returns dest to allow chaining operations.
func (dest *primeFieldElement) Mul(lhs, rhs *primeFieldElement) *primeFieldElement {
a := &lhs.A // = a*R
b := &rhs.A // = b*R
var ab FpElementX2
fp503Mul(&ab, a, b) // = a*b*R*R
fp503MontgomeryReduce(&dest.A, &ab) // = a*b*R mod p
return dest
}
// Set dest = x^(2^k), for k >= 1, by repeated squarings.
//
// Allowed to overlap x with dest.
//
// Returns dest to allow chaining operations.
func (dest *primeFieldElement) Pow2k(x *primeFieldElement, k uint8) *primeFieldElement {
dest.Mul(x, x)
for i := uint8(1); i < k; i++ {
dest.Mul(dest, dest)
}
return dest
}
// Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x).
// Uses variation of sliding-window algorithm from with window size
// of 5 and least to most significant bit sliding (left-to-right)
// See HAC 14.85 for general description.
//
// Allowed to overlap x with dest.
//
// Returns dest to allow chaining operations.
func (dest *primeFieldElement) P34(x *primeFieldElement) *primeFieldElement {
// Sliding-window strategy computed with etc/scripts/sliding_window_strat_calc.py
//
// This performs sum(powStrategy) + 1 squarings and len(lookup) + len(mulStrategy)
// multiplications.
powStrategy := []uint8{1, 12, 5, 5, 2, 7, 11, 3, 8, 4, 11, 4, 7, 5, 6, 3, 7, 5, 7, 2, 12, 5, 6, 4, 6, 8, 6, 4, 7, 5, 5, 8, 5, 8, 5, 5, 8, 9, 3, 6, 2, 10, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3}
mulStrategy := []uint8{0, 12, 11, 10, 0, 1, 8, 3, 7, 1, 8, 3, 6, 7, 14, 2, 14, 14, 9, 0, 13, 9, 15, 5, 12, 7, 13, 7, 15, 6, 7, 9, 0, 5, 7, 6, 8, 8, 3, 7, 0, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3}
// Precompute lookup table of odd multiples of x for window
// size k=5.
lookup := [16]primeFieldElement{}
xx := &primeFieldElement{}
xx.Mul(x, x)
lookup[0] = *x
for i := 1; i < 16; i++ {
lookup[i].Mul(&lookup[i-1], xx)
}
// Now lookup = {x, x^3, x^5, ... }
// so that lookup[i] = x^{2*i + 1}
// so that lookup[k/2] = x^k, for odd k
*dest = lookup[mulStrategy[0]]
for i := uint8(1); i < uint8(len(powStrategy)); i++ {
dest.Pow2k(dest, powStrategy[i])
dest.Mul(dest, &lookup[mulStrategy[i]])
}
return dest
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +0,0 @@
// +build amd64,!noasm arm64,!noasm
package p751
import (
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
)
// If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x.
// If choice is neither 0 nor 1 then behaviour is undefined.
// This function executes in constant time.
//go:noescape
func fp751ConditionalSwap(x, y *FpElement, choice uint8)
// Compute z = x + y (mod p).
//go:noescape
func fp751AddReduced(z, x, y *FpElement)
// Compute z = x - y (mod p).
//go:noescape
func fp751SubReduced(z, x, y *FpElement)
// Compute z = x + y, without reducing mod p.
//go:noescape
func fp751AddLazy(z, x, y *FpElement)
// Compute z = x + y, without reducing mod p.
//go:noescape
func fp751X2AddLazy(z, x, y *FpElementX2)
// Compute z = x - y, without reducing mod p.
//go:noescape
func fp751X2SubLazy(z, x, y *FpElementX2)
// Compute z = x * y.
//go:noescape
func fp751Mul(z *FpElementX2, x, y *FpElement)
// Compute Montgomery reduction: set z = x * R^{-1} (mod 2*p).
// It may destroy the input value.
//go:noescape
func fp751MontgomeryReduce(z *FpElement, x *FpElementX2)
// Reduce a field element in [0, 2*p) to one in [0,p).
//go:noescape
func fp751StrongReduce(x *FpElement)

View File

@ -1,196 +0,0 @@
// +build noasm !amd64,!arm64
package p751
import (
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/arith"
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
)
// Compute z = x + y (mod p).
func fp751AddReduced(z, x, y *FpElement) {
var carry uint64
// z=x+y % p751
for i := 0; i < NumWords; i++ {
z[i], carry = Addc64(carry, x[i], y[i])
}
// z = z - p751x2
carry = 0
for i := 0; i < NumWords; i++ {
z[i], carry = Subc64(carry, z[i], p751x2[i])
}
// z = z + p751x2
mask := uint64(0 - carry)
carry = 0
for i := 0; i < NumWords; i++ {
z[i], carry = Addc64(carry, z[i], p751x2[i]&mask)
}
}
// Compute z = x - y (mod p).
func fp751SubReduced(z, x, y *FpElement) {
var borrow uint64
for i := 0; i < NumWords; i++ {
z[i], borrow = Subc64(borrow, x[i], y[i])
}
mask := uint64(0 - borrow)
borrow = 0
for i := 0; i < NumWords; i++ {
z[i], borrow = Addc64(borrow, z[i], p751x2[i]&mask)
}
}
// Conditionally swaps bits in x and y in constant time.
// mask indicates bits to be swaped (set bits are swapped)
// For details see "Hackers Delight, 2.20"
//
// Implementation doesn't actually depend on a prime field.
func fp751ConditionalSwap(x, y *FpElement, mask uint8) {
var tmp, mask64 uint64
mask64 = 0 - uint64(mask)
for i := 0; i < len(x); i++ {
tmp = mask64 & (x[i] ^ y[i])
x[i] = tmp ^ x[i]
y[i] = tmp ^ y[i]
}
}
// Perform Montgomery reduction: set z = x R^{-1} (mod 2*p)
// with R=2^768. Destroys the input value.
func fp751MontgomeryReduce(z *FpElement, x *FpElementX2) {
var carry, t, u, v uint64
var uv Uint128
var count int
count = 5 // number of 0 digits in the least significat part of p751 + 1
for i := 0; i < NumWords; i++ {
for j := 0; j < i; j++ {
if j < (i - count + 1) {
uv = Mul64(z[j], p751p1[i-j])
v, carry = Addc64(0, uv.L, v)
u, carry = Addc64(carry, uv.H, u)
t += carry
}
}
v, carry = Addc64(0, v, x[i])
u, carry = Addc64(carry, u, 0)
t += carry
z[i] = v
v = u
u = t
t = 0
}
for i := NumWords; i < 2*NumWords-1; i++ {
if count > 0 {
count--
}
for j := i - NumWords + 1; j < NumWords; j++ {
if j < (NumWords - count) {
uv = Mul64(z[j], p751p1[i-j])
v, carry = Addc64(0, uv.L, v)
u, carry = Addc64(carry, uv.H, u)
t += carry
}
}
v, carry = Addc64(0, v, x[i])
u, carry = Addc64(carry, u, 0)
t += carry
z[i-NumWords] = v
v = u
u = t
t = 0
}
v, carry = Addc64(0, v, x[2*NumWords-1])
z[NumWords-1] = v
}
// Compute z = x * y.
func fp751Mul(z *FpElementX2, x, y *FpElement) {
var u, v, t uint64
var carry uint64
var uv Uint128
for i := uint64(0); i < NumWords; i++ {
for j := uint64(0); j <= i; j++ {
uv = Mul64(x[j], y[i-j])
v, carry = Addc64(0, uv.L, v)
u, carry = Addc64(carry, uv.H, u)
t += carry
}
z[i] = v
v = u
u = t
t = 0
}
for i := NumWords; i < (2*NumWords)-1; i++ {
for j := i - NumWords + 1; j < NumWords; j++ {
uv = Mul64(x[j], y[i-j])
v, carry = Addc64(0, uv.L, v)
u, carry = Addc64(carry, uv.H, u)
t += carry
}
z[i] = v
v = u
u = t
t = 0
}
z[2*NumWords-1] = v
}
// Compute z = x + y, without reducing mod p.
func fp751AddLazy(z, x, y *FpElement) {
var carry uint64
for i := 0; i < NumWords; i++ {
z[i], carry = Addc64(carry, x[i], y[i])
}
}
// Compute z = x + y, without reducing mod p.
func fp751X2AddLazy(z, x, y *FpElementX2) {
var carry uint64
for i := 0; i < 2*NumWords; i++ {
z[i], carry = Addc64(carry, x[i], y[i])
}
}
// Reduce a field element in [0, 2*p) to one in [0,p).
func fp751StrongReduce(x *FpElement) {
var borrow, mask uint64
for i := 0; i < NumWords; i++ {
x[i], borrow = Subc64(borrow, x[i], p751[i])
}
// Sets all bits if borrow = 1
mask = 0 - borrow
borrow = 0
for i := 0; i < NumWords; i++ {
x[i], borrow = Addc64(borrow, x[i], p751[i]&mask)
}
}
// Compute z = x - y, without reducing mod p.
func fp751X2SubLazy(z, x, y *FpElementX2) {
var borrow, mask uint64
for i := 0; i < len(z); i++ {
z[i], borrow = Subc64(borrow, x[i], y[i])
}
// Sets all bits if borrow = 1
mask = 0 - borrow
borrow = 0
for i := NumWords; i < len(z); i++ {
z[i], borrow = Addc64(borrow, z[i], p751[i-NumWords]&mask)
}
}

View File

@ -1,227 +0,0 @@
package p751
import (
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
cpu "v2ray.com/core/external/github.com/cloudflare/sidh/internal/utils"
)
const (
// SIDH public key byte size
P751_PublicKeySize = 564
// SIDH shared secret byte size.
P751_SharedSecretSize = 188
// Max size of secret key for 2-torsion group, corresponds to 2^e2
P751_SecretBitLenA = 372
// Size of secret key for 3-torsion group, corresponds to floor(log_2(3^e3))
P751_SecretBitLenB = 378
// P751 bytelen ceil(751/8)
P751_Bytelen = 94
// Size of a compuatation strategy for 2-torsion group
strategySizeA = 185
// Size of a compuatation strategy for 3-torsion group
strategySizeB = 238
// Number of 64-bit limbs used to store Fp element
NumWords = 12
)
// CPU Capabilities. Those flags are referred by assembly code. According to
// https://github.com/golang/go/issues/28230, variables referred from the
// assembly must be in the same package.
// We declare them variables not constants in order to facilitate testing.
var (
// Signals support for MULX which is in BMI2
HasBMI2 = cpu.X86.HasBMI2
// Signals support for ADX and BMI2
HasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX
)
// The x-coordinate of PA
var P751_affine_PA = Fp2Element{
A: FpElement{
0xC2FC08CEAB50AD8B, 0x1D7D710F55E457B1, 0xE8738D92953DCD6E,
0xBAA7EBEE8A3418AA, 0xC9A288345F03F46F, 0xC8D18D167CFE2616,
0x02043761F6B1C045, 0xAA1975E13180E7E9, 0x9E13D3FDC6690DE6,
0x3A024640A3A3BB4F, 0x4E5AD44E6ACBBDAE, 0x0000544BEB561DAD,
},
B: FpElement{
0xE6CC41D21582E411, 0x07C2ECB7C5DF400A, 0xE8E34B521432AEC4,
0x50761E2AB085167D, 0x032CFBCAA6094B3C, 0x6C522F5FDF9DDD71,
0x1319217DC3A1887D, 0xDC4FB25803353A86, 0x362C8D7B63A6AB09,
0x39DCDFBCE47EA488, 0x4C27C99A2C28D409, 0x00003CB0075527C4,
},
}
// The x-coordinate of QA
var P751_affine_QA = Fp2Element{
A: FpElement{
0xD56FE52627914862, 0x1FAD60DC96B5BAEA, 0x01E137D0BF07AB91,
0x404D3E9252161964, 0x3C5385E4CD09A337, 0x4476426769E4AF73,
0x9790C6DB989DFE33, 0xE06E1C04D2AA8B5E, 0x38C08185EDEA73B9,
0xAA41F678A4396CA6, 0x92B9259B2229E9A0, 0x00002F9326818BE0,
},
B: FpElement{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
},
}
// The x-coordinate of RA = PA-QA
var P751_affine_RA = Fp2Element{
A: FpElement{
0x0BB84441DFFD19B3, 0x84B4DEA99B48C18E, 0x692DE648AD313805,
0xE6D72761B6DFAEE0, 0x223975C672C3058D, 0xA0FDE0C3CBA26FDC,
0xA5326132A922A3CA, 0xCA5E7F5D5EA96FA4, 0x127C7EFE33FFA8C6,
0x4749B1567E2A23C4, 0x2B7DF5B4AF413BFA, 0x0000656595B9623C,
},
B: FpElement{
0xED78C17F1EC71BE8, 0xF824D6DF753859B1, 0x33A10839B2A8529F,
0xFC03E9E25FDEA796, 0xC4708A8054DF1762, 0x4034F2EC034C6467,
0xABFB70FBF06ECC79, 0xDABE96636EC108B7, 0x49CBCFB090605FD3,
0x20B89711819A45A7, 0xFB8E1590B2B0F63E, 0x0000556A5F964AB2,
},
}
// The x-coordinate of PB
var P751_affine_PB = Fp2Element{
A: FpElement{
0xCFB6D71EF867AB0B, 0x4A5FDD76E9A45C76, 0x38B1EE69194B1F03,
0xF6E7B18A7761F3F0, 0xFCF01A486A52C84C, 0xCBE2F63F5AA75466,
0x6487BCE837B5E4D6, 0x7747F5A8C622E9B8, 0x4CBFE1E4EE6AEBBA,
0x8A8616A13FA91512, 0x53DB980E1579E0A5, 0x000058FEBFF3BE69,
},
B: FpElement{
0xA492034E7C075CC3, 0x677BAF00B04AA430, 0x3AAE0C9A755C94C8,
0x1DC4B064E9EBB08B, 0x3684EDD04E826C66, 0x9BAA6CB661F01B22,
0x20285A00AD2EFE35, 0xDCE95ABD0497065F, 0x16C7FBB3778E3794,
0x26B3AC29CEF25AAF, 0xFB3C28A31A30AC1D, 0x000046ED190624EE,
},
}
// The x-coordinate of QB
var P751_affine_QB = Fp2Element{
A: FpElement{
0xF1A8C9ED7B96C4AB, 0x299429DA5178486E, 0xEF4926F20CD5C2F4,
0x683B2E2858B4716A, 0xDDA2FBCC3CAC3EEB, 0xEC055F9F3A600460,
0xD5A5A17A58C3848B, 0x4652D836F42EAED5, 0x2F2E71ED78B3A3B3,
0xA771C057180ADD1D, 0xC780A5D2D835F512, 0x0000114EA3B55AC1,
},
B: FpElement{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
},
}
// The x-coordinate of RB = PB - QB
var P751_affine_RB = Fp2Element{
A: FpElement{
0x1C0D6733769D0F31, 0xF084C3086E2659D1, 0xE23D5DA27BCBD133,
0xF38EC9A8D5864025, 0x6426DC781B3B645B, 0x4B24E8E3C9FB03EE,
0x6432792F9D2CEA30, 0x7CC8E8B1AE76E857, 0x7F32BFB626BB8963,
0xB9F05995B48D7B74, 0x4D71200A7D67E042, 0x0000228457AF0637,
},
B: FpElement{
0x4AE37E7D8F72BD95, 0xDD2D504B3E993488, 0x5D14E7FA1ECB3C3E,
0x127610CEB75D6350, 0x255B4B4CAC446B11, 0x9EA12336C1F70CAF,
0x79FA68A2147BC2F8, 0x11E895CFDADBBC49, 0xE4B9D3C4D6356C18,
0x44B25856A67F951C, 0x5851541F61308D0B, 0x00002FFD994F7E4C,
},
}
// 2-torsion group computation strategy
var P751_AliceIsogenyStrategy = [strategySizeA]uint32{
0x50, 0x30, 0x1B, 0x0F, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02,
0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x07,
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x01,
0x01, 0x01, 0x01, 0x0C, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02,
0x01, 0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x05, 0x03,
0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x15,
0x0C, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03,
0x02, 0x01, 0x01, 0x01, 0x01, 0x05, 0x03, 0x02, 0x01, 0x01,
0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, 0x05, 0x03, 0x02,
0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02,
0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x21, 0x14, 0x0C, 0x07,
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x01,
0x01, 0x01, 0x01, 0x05, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x01, 0x08, 0x05, 0x03, 0x02, 0x01, 0x01,
0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01,
0x02, 0x01, 0x01, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02,
0x01, 0x01, 0x02, 0x01, 0x01}
// 3-torsion group computation strategy
var P751_BobIsogenyStrategy = [strategySizeB]uint32{
0x70, 0x3F, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02,
0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08,
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01,
0x01, 0x02, 0x01, 0x01, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01,
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02,
0x01, 0x01, 0x02, 0x01, 0x01, 0x1F, 0x10, 0x08, 0x04, 0x02,
0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02,
0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x0F, 0x08, 0x04,
0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01,
0x02, 0x01, 0x01, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x31, 0x1F, 0x10,
0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02,
0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01,
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x0F, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04,
0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x07, 0x04, 0x02, 0x01,
0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
0x15, 0x0C, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x05, 0x03, 0x02,
0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, 0x05,
0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01}
// Used internally by this package. Not consts as Go doesn't allow arrays to be consts
// -------------------------------
// p751
var p751 = FpElement{
0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
0xffffffffffffffff, 0xffffffffffffffff, 0xeeafffffffffffff,
0xe3ec968549f878a8, 0xda959b1a13f7cc76, 0x084e9867d6ebe876,
0x8562b5045cb25748, 0x0e12909f97badc66, 0x00006fe5d541f71c}
// 2*p751
var p751x2 = FpElement{
0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xDD5FFFFFFFFFFFFF,
0xC7D92D0A93F0F151, 0xB52B363427EF98ED, 0x109D30CFADD7D0ED,
0x0AC56A08B964AE90, 0x1C25213F2F75B8CD, 0x0000DFCBAA83EE38}
// p751 + 1
var p751p1 = FpElement{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0xeeb0000000000000,
0xe3ec968549f878a8, 0xda959b1a13f7cc76, 0x084e9867d6ebe876,
0x8562b5045cb25748, 0x0e12909f97badc66, 0x00006fe5d541f71c}
// R^2 = (2^768)^2 mod p
var p751R2 = FpElement{
2535603850726686808, 15780896088201250090, 6788776303855402382,
17585428585582356230, 5274503137951975249, 2266259624764636289,
11695651972693921304, 13072885652150159301, 4908312795585420432,
6229583484603254826, 488927695601805643, 72213483953973}
// 1*R mod p
var P751_OneFp2 = Fp2Element{
A: FpElement{
0x249ad, 0x0, 0x0, 0x0, 0x0, 0x8310000000000000, 0x5527b1e4375c6c66, 0x697797bf3f4f24d0, 0xc89db7b2ac5c4e2e, 0x4ca4b439d2076956, 0x10f7926c7512c7e9, 0x2d5b24bce5e2},
}
// 1/2 * R mod p
var P751_HalfFp2 = Fp2Element{
A: FpElement{
0x00000000000124D6, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0xB8E0000000000000,
0x9C8A2434C0AA7287, 0xA206996CA9A378A3, 0x6876280D41A41B52,
0xE903B49F175CE04F, 0x0F8511860666D227, 0x00004EA07CFF6E7F},
}

View File

@ -1,254 +0,0 @@
package p751
import . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
// 2*p751
var ()
//------------------------------------------------------------------------------
// Implementtaion of FieldOperations
//------------------------------------------------------------------------------
// Implements FieldOps
type fp751Ops struct{}
func FieldOperations() FieldOps {
return &fp751Ops{}
}
func (fp751Ops) Add(dest, lhs, rhs *Fp2Element) {
fp751AddReduced(&dest.A, &lhs.A, &rhs.A)
fp751AddReduced(&dest.B, &lhs.B, &rhs.B)
}
func (fp751Ops) Sub(dest, lhs, rhs *Fp2Element) {
fp751SubReduced(&dest.A, &lhs.A, &rhs.A)
fp751SubReduced(&dest.B, &lhs.B, &rhs.B)
}
func (fp751Ops) Mul(dest, lhs, rhs *Fp2Element) {
// Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b).
a := &lhs.A
b := &lhs.B
c := &rhs.A
d := &rhs.B
// We want to compute
//
// (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i
//
// Use Karatsuba's trick: note that
//
// (b - a)*(c - d) = (b*c + a*d) - a*c - b*d
//
// so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d.
var ac, bd FpElementX2
fp751Mul(&ac, a, c) // = a*c*R*R
fp751Mul(&bd, b, d) // = b*d*R*R
var b_minus_a, c_minus_d FpElement
fp751SubReduced(&b_minus_a, b, a) // = (b-a)*R
fp751SubReduced(&c_minus_d, c, d) // = (c-d)*R
var ad_plus_bc FpElementX2
fp751Mul(&ad_plus_bc, &b_minus_a, &c_minus_d) // = (b-a)*(c-d)*R*R
fp751X2AddLazy(&ad_plus_bc, &ad_plus_bc, &ac) // = ((b-a)*(c-d) + a*c)*R*R
fp751X2AddLazy(&ad_plus_bc, &ad_plus_bc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R
fp751MontgomeryReduce(&dest.B, &ad_plus_bc) // = (a*d + b*c)*R mod p
var ac_minus_bd FpElementX2
fp751X2SubLazy(&ac_minus_bd, &ac, &bd) // = (a*c - b*d)*R*R
fp751MontgomeryReduce(&dest.A, &ac_minus_bd) // = (a*c - b*d)*R mod p
}
func (fp751Ops) Square(dest, x *Fp2Element) {
a := &x.A
b := &x.B
// We want to compute
//
// (a + bi)*(a + bi) = (a^2 - b^2) + 2abi.
var a2, a_plus_b, a_minus_b FpElement
fp751AddReduced(&a2, a, a) // = a*R + a*R = 2*a*R
fp751AddReduced(&a_plus_b, a, b) // = a*R + b*R = (a+b)*R
fp751SubReduced(&a_minus_b, a, b) // = a*R - b*R = (a-b)*R
var asq_minus_bsq, ab2 FpElementX2
fp751Mul(&asq_minus_bsq, &a_plus_b, &a_minus_b) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R
fp751Mul(&ab2, &a2, b) // = 2*a*b*R*R
fp751MontgomeryReduce(&dest.A, &asq_minus_bsq) // = (a^2 - b^2)*R mod p
fp751MontgomeryReduce(&dest.B, &ab2) // = 2*a*b*R mod p
}
// Set dest = 1/x
//
// Allowed to overlap dest with x.
//
// Returns dest to allow chaining operations.
func (fp751Ops) Inv(dest, x *Fp2Element) {
a := &x.A
b := &x.B
// We want to compute
//
// 1 1 (a - bi) (a - bi)
// -------- = -------- -------- = -----------
// (a + bi) (a + bi) (a - bi) (a^2 + b^2)
//
// Letting c = 1/(a^2 + b^2), this is
//
// 1/(a+bi) = a*c - b*ci.
var asq_plus_bsq primeFieldElement
var asq, bsq FpElementX2
fp751Mul(&asq, a, a) // = a*a*R*R
fp751Mul(&bsq, b, b) // = b*b*R*R
fp751X2AddLazy(&asq, &asq, &bsq) // = (a^2 + b^2)*R*R
fp751MontgomeryReduce(&asq_plus_bsq.A, &asq) // = (a^2 + b^2)*R mod p
// Now asq_plus_bsq = a^2 + b^2
// Invert asq_plus_bsq
inv := asq_plus_bsq
inv.Mul(&asq_plus_bsq, &asq_plus_bsq)
inv.P34(&inv)
inv.Mul(&inv, &inv)
inv.Mul(&inv, &asq_plus_bsq)
var ac FpElementX2
fp751Mul(&ac, a, &inv.A)
fp751MontgomeryReduce(&dest.A, &ac)
var minus_b FpElement
fp751SubReduced(&minus_b, &minus_b, b)
var minus_bc FpElementX2
fp751Mul(&minus_bc, &minus_b, &inv.A)
fp751MontgomeryReduce(&dest.B, &minus_bc)
}
// In case choice == 1, performs following swap in constant time:
// xPx <-> xQx
// xPz <-> xQz
// Otherwise returns xPx, xPz, xQx, xQz unchanged
func (fp751Ops) CondSwap(xPx, xPz, xQx, xQz *Fp2Element, choice uint8) {
fp751ConditionalSwap(&xPx.A, &xQx.A, choice)
fp751ConditionalSwap(&xPx.B, &xQx.B, choice)
fp751ConditionalSwap(&xPz.A, &xQz.A, choice)
fp751ConditionalSwap(&xPz.B, &xQz.B, choice)
}
// Converts values in x.A and x.B to Montgomery domain
// x.A = x.A * R mod p
// x.B = x.B * R mod p
func (fp751Ops) ToMontgomery(x *Fp2Element) {
var aRR FpElementX2
// convert to montgomery domain
fp751Mul(&aRR, &x.A, &p751R2) // = a*R*R
fp751MontgomeryReduce(&x.A, &aRR) // = a*R mod p
fp751Mul(&aRR, &x.B, &p751R2)
fp751MontgomeryReduce(&x.B, &aRR)
}
// Converts values in x.A and x.B from Montgomery domain
// a = x.A mod p
// b = x.B mod p
//
// After returning from the call x is not modified.
func (fp751Ops) FromMontgomery(x *Fp2Element, out *Fp2Element) {
var aR FpElementX2
// convert from montgomery domain
copy(aR[:], x.A[:])
fp751MontgomeryReduce(&out.A, &aR) // = a mod p in [0, 2p)
fp751StrongReduce(&out.A) // = a mod p in [0, p)
for i := range aR {
aR[i] = 0
}
copy(aR[:], x.B[:])
fp751MontgomeryReduce(&out.B, &aR)
fp751StrongReduce(&out.B)
}
//------------------------------------------------------------------------------
// Prime Field
//------------------------------------------------------------------------------
// Represents an element of the prime field F_p in Montgomery domain
type primeFieldElement struct {
// The value `A`is represented by `aR mod p`.
A FpElement
}
// Set dest = lhs * rhs.
//
// Allowed to overlap lhs or rhs with dest.
//
// Returns dest to allow chaining operations.
func (dest *primeFieldElement) Mul(lhs, rhs *primeFieldElement) *primeFieldElement {
a := &lhs.A // = a*R
b := &rhs.A // = b*R
var ab FpElementX2
fp751Mul(&ab, a, b) // = a*b*R*R
fp751MontgomeryReduce(&dest.A, &ab) // = a*b*R mod p
return dest
}
// Set dest = x^(2^k), for k >= 1, by repeated squarings.
//
// Allowed to overlap x with dest.
//
// Returns dest to allow chaining operations.
func (dest *primeFieldElement) Pow2k(x *primeFieldElement, k uint8) *primeFieldElement {
dest.Mul(x, x)
for i := uint8(1); i < k; i++ {
dest.Mul(dest, dest)
}
return dest
}
// Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x).
//
// Allowed to overlap x with dest.
//
// Returns dest to allow chaining operations.
func (dest *primeFieldElement) P34(x *primeFieldElement) *primeFieldElement {
// Sliding-window strategy computed with Sage, awk, sed, and tr.
//
// This performs sum(powStrategy) = 744 squarings and len(mulStrategy)
// = 137 multiplications, in addition to 1 squaring and 15
// multiplications to build a lookup table.
//
// In total this is 745 squarings, 152 multiplications. Since squaring
// is not implemented for the prime field, this is 897 multiplications
// in total.
powStrategy := [137]uint8{5, 7, 6, 2, 10, 4, 6, 9, 8, 5, 9, 4, 7, 5, 5, 4, 8, 3, 9, 5, 5, 4, 10, 4, 6, 6, 6, 5, 8, 9, 3, 4, 9, 4, 5, 6, 6, 2, 9, 4, 5, 5, 5, 7, 7, 9, 4, 6, 4, 8, 5, 8, 6, 6, 2, 9, 7, 4, 8, 8, 8, 4, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2}
mulStrategy := [137]uint8{31, 23, 21, 1, 31, 7, 7, 7, 9, 9, 19, 15, 23, 23, 11, 7, 25, 5, 21, 17, 11, 5, 17, 7, 11, 9, 23, 9, 1, 19, 5, 3, 25, 15, 11, 29, 31, 1, 29, 11, 13, 9, 11, 27, 13, 19, 15, 31, 3, 29, 23, 31, 25, 11, 1, 21, 19, 15, 15, 21, 29, 13, 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 3}
initialMul := uint8(27)
// Build a lookup table of odd multiples of x.
lookup := [16]primeFieldElement{}
xx := &primeFieldElement{}
xx.Mul(x, x) // Set xx = x^2
lookup[0] = *x
for i := 1; i < 16; i++ {
lookup[i].Mul(&lookup[i-1], xx)
}
// Now lookup = {x, x^3, x^5, ... }
// so that lookup[i] = x^{2*i + 1}
// so that lookup[k/2] = x^k, for odd k
*dest = lookup[initialMul/2]
for i := uint8(0); i < 137; i++ {
dest.Pow2k(dest, powStrategy[i])
dest.Mul(dest, &lookup[mulStrategy[i]/2])
}
return dest
}

View File

@ -1,226 +0,0 @@
package sidh
import (
"errors"
"io"
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
)
// I keep it bool in order to be able to apply logical NOT
type KeyVariant uint
// Id's correspond to bitlength of the prime field characteristic
// Currently FP_751 is the only one supported by this implementation
const (
FP_503 uint8 = iota
FP_751
FP_964
maxPrimeFieldId
)
const (
// First 2 bits identify SIDH variant third bit indicates
// wether key is a SIKE variant (set) or SIDH (not set)
// 001 - SIDH: corresponds to 2-torsion group
KeyVariant_SIDH_A KeyVariant = 1 << 0
// 010 - SIDH: corresponds to 3-torsion group
KeyVariant_SIDH_B = 1 << 1
// 110 - SIKE
KeyVariant_SIKE = 1<<2 | KeyVariant_SIDH_B
)
// Base type for public and private key. Used mainly to carry domain
// parameters.
type key struct {
// Domain parameters of the algorithm to be used with a key
params *SidhParams
// Flag indicates wether corresponds to 2-, 3-torsion group or SIKE
keyVariant KeyVariant
}
// Defines operations on public key
type PublicKey struct {
key
affine_xP Fp2Element
affine_xQ Fp2Element
affine_xQmP Fp2Element
}
// Defines operations on private key
type PrivateKey struct {
key
// Secret key
Scalar []byte
// Used only by KEM
S []byte
}
// Accessor to the domain parameters
func (key *key) Params() *SidhParams {
return key.params
}
// Accessor to key variant
func (key *key) Variant() KeyVariant {
return key.keyVariant
}
// NewPrivateKey initializes private key.
// Usage of this function guarantees that the object is correctly initialized.
func NewPrivateKey(id uint8, v KeyVariant) *PrivateKey {
prv := &PrivateKey{key: key{params: Params(id), keyVariant: v}}
if (v & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
prv.Scalar = make([]byte, prv.params.A.SecretByteLen)
} else {
prv.Scalar = make([]byte, prv.params.B.SecretByteLen)
}
if v == KeyVariant_SIKE {
prv.S = make([]byte, prv.params.MsgLen)
}
return prv
}
// NewPublicKey initializes public key.
// Usage of this function guarantees that the object is correctly initialized.
func NewPublicKey(id uint8, v KeyVariant) *PublicKey {
return &PublicKey{key: key{params: Params(id), keyVariant: v}}
}
// Import clears content of the public key currently stored in the structure
// and imports key stored in the byte string. Returns error in case byte string
// size is wrong. Doesn't perform any validation.
func (pub *PublicKey) Import(input []byte) error {
if len(input) != pub.Size() {
return errors.New("sidh: input to short")
}
op := CurveOperations{Params: pub.params}
ssSz := pub.params.SharedSecretSize
op.Fp2FromBytes(&pub.affine_xP, input[0:ssSz])
op.Fp2FromBytes(&pub.affine_xQ, input[ssSz:2*ssSz])
op.Fp2FromBytes(&pub.affine_xQmP, input[2*ssSz:3*ssSz])
return nil
}
// Exports currently stored key. In case structure hasn't been filled with key data
// returned byte string is filled with zeros.
func (pub *PublicKey) Export() []byte {
output := make([]byte, pub.params.PublicKeySize)
op := CurveOperations{Params: pub.params}
ssSz := pub.params.SharedSecretSize
op.Fp2ToBytes(output[0:ssSz], &pub.affine_xP)
op.Fp2ToBytes(output[ssSz:2*ssSz], &pub.affine_xQ)
op.Fp2ToBytes(output[2*ssSz:3*ssSz], &pub.affine_xQmP)
return output
}
// Size returns size of the public key in bytes
func (pub *PublicKey) Size() int {
return pub.params.PublicKeySize
}
// Exports currently stored key. In case structure hasn't been filled with key data
// returned byte string is filled with zeros.
func (prv *PrivateKey) Export() []byte {
ret := make([]byte, len(prv.Scalar)+len(prv.S))
copy(ret, prv.S)
copy(ret[len(prv.S):], prv.Scalar)
return ret
}
// Size returns size of the private key in bytes
func (prv *PrivateKey) Size() int {
tmp := len(prv.Scalar)
if prv.Variant() == KeyVariant_SIKE {
tmp += int(prv.params.MsgLen)
}
return tmp
}
// Import clears content of the private key currently stored in the structure
// and imports key from octet string. In case of SIKE, the random value 'S'
// must be prepended to the value of actual private key (see SIKE spec for details).
// Function doesn't import public key value to PrivateKey object.
func (prv *PrivateKey) Import(input []byte) error {
if len(input) != prv.Size() {
return errors.New("sidh: input to short")
}
copy(prv.S, input[:len(prv.S)])
copy(prv.Scalar, input[len(prv.S):])
return nil
}
// Generates random private key for SIDH or SIKE. Generated value is
// formed as little-endian integer from key-space <2^(e2-1)..2^e2 - 1>
// for KeyVariant_A or <2^(s-1)..2^s - 1>, where s = floor(log_2(3^e3)),
// for KeyVariant_B.
//
// Returns error in case user provided RNG fails.
func (prv *PrivateKey) Generate(rand io.Reader) error {
var err error
var dp *DomainParams
if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
dp = &prv.params.A
} else {
dp = &prv.params.B
}
if prv.keyVariant == KeyVariant_SIKE && err == nil {
_, err = io.ReadFull(rand, prv.S)
}
// Private key generation takes advantage of the fact that keyspace for secret
// key is (0, 2^x - 1), for some possitivite value of 'x' (see SIKE, 1.3.8).
// It means that all bytes in the secret key, but the last one, can take any
// value between <0x00,0xFF>. Similarily for the last byte, but generation
// needs to chop off some bits, to make sure generated value is an element of
// a key-space.
_, err = io.ReadFull(rand, prv.Scalar)
if err != nil {
return err
}
prv.Scalar[len(prv.Scalar)-1] &= (1 << (dp.SecretBitLen % 8)) - 1
// Make sure scalar is SecretBitLen long. SIKE spec says that key
// space starts from 0, but I'm not confortable with having low
// value scalars used for private keys. It is still secrure as per
// table 5.1 in [SIKE].
prv.Scalar[len(prv.Scalar)-1] |= 1 << ((dp.SecretBitLen % 8) - 1)
return err
}
// Generates public key.
//
// Constant time.
func (prv *PrivateKey) GeneratePublicKey() *PublicKey {
if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
return publicKeyGenA(prv)
}
return publicKeyGenB(prv)
}
// Computes a shared secret which is a j-invariant. Function requires that pub has
// different KeyVariant than prv. Length of returned output is 2*ceil(log_2 P)/8),
// where P is a prime defining finite field.
//
// It's important to notice that each keypair must not be used more than once
// to calculate shared secret.
//
// Function may return error. This happens only in case provided input is invalid.
// Constant time for properly initialized private and public key.
func DeriveSecret(prv *PrivateKey, pub *PublicKey) ([]byte, error) {
if (pub == nil) || (prv == nil) {
return nil, errors.New("sidh: invalid arguments")
}
if (pub.keyVariant == prv.keyVariant) || (pub.params.Id != prv.params.Id) {
return nil, errors.New("sidh: public and private are incompatbile")
}
if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
return deriveSecretA(prv, pub), nil
} else {
return deriveSecretB(prv, pub), nil
}
}

View File

@ -1,82 +0,0 @@
package sidh
import (
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
p503 "v2ray.com/core/external/github.com/cloudflare/sidh/p503"
p751 "v2ray.com/core/external/github.com/cloudflare/sidh/p751"
)
// Keeps mapping: SIDH prime field ID to domain parameters
var sidhParams = make(map[uint8]SidhParams)
// Params returns domain parameters corresponding to finite field and identified by
// `id` provieded by the caller. Function panics in case `id` wasn't registered earlier.
func Params(id uint8) *SidhParams {
if val, ok := sidhParams[id]; ok {
return &val
}
panic("sidh: SIDH Params ID unregistered")
}
func init() {
p503 := SidhParams{
Id: FP_503,
PublicKeySize: p503.P503_PublicKeySize,
SharedSecretSize: p503.P503_SharedSecretSize,
A: DomainParams{
Affine_P: p503.P503_affine_PA,
Affine_Q: p503.P503_affine_QA,
Affine_R: p503.P503_affine_RA,
SecretBitLen: p503.P503_SecretBitLenA,
SecretByteLen: uint((p503.P503_SecretBitLenA + 7) / 8),
IsogenyStrategy: p503.P503_AliceIsogenyStrategy[:],
},
B: DomainParams{
Affine_P: p503.P503_affine_PB,
Affine_Q: p503.P503_affine_QB,
Affine_R: p503.P503_affine_RB,
SecretBitLen: p503.P503_SecretBitLenB,
SecretByteLen: uint((p503.P503_SecretBitLenB + 7) / 8),
IsogenyStrategy: p503.P503_BobIsogenyStrategy[:],
},
OneFp2: p503.P503_OneFp2,
HalfFp2: p503.P503_HalfFp2,
MsgLen: 24,
// SIKEp751 provides 128 bit of classical security ([SIKE], 5.1)
KemSize: 16,
Bytelen: p503.P503_Bytelen,
Op: p503.FieldOperations(),
}
p751 := SidhParams{
Id: FP_751,
PublicKeySize: p751.P751_PublicKeySize,
SharedSecretSize: p751.P751_SharedSecretSize,
A: DomainParams{
Affine_P: p751.P751_affine_PA,
Affine_Q: p751.P751_affine_QA,
Affine_R: p751.P751_affine_RA,
IsogenyStrategy: p751.P751_AliceIsogenyStrategy[:],
SecretBitLen: p751.P751_SecretBitLenA,
SecretByteLen: uint((p751.P751_SecretBitLenA + 7) / 8),
},
B: DomainParams{
Affine_P: p751.P751_affine_PB,
Affine_Q: p751.P751_affine_QB,
Affine_R: p751.P751_affine_RB,
IsogenyStrategy: p751.P751_BobIsogenyStrategy[:],
SecretBitLen: p751.P751_SecretBitLenB,
SecretByteLen: uint((p751.P751_SecretBitLenB + 7) / 8),
},
OneFp2: p751.P751_OneFp2,
HalfFp2: p751.P751_HalfFp2,
MsgLen: 32,
// SIKEp751 provides 192 bit of classical security ([SIKE], 5.1)
KemSize: 24,
Bytelen: p751.P751_Bytelen,
Op: p751.FieldOperations(),
}
sidhParams[FP_503] = p503
sidhParams[FP_751] = p751
}

View File

@ -1,302 +0,0 @@
package sidh
import (
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
)
// -----------------------------------------------------------------------------
// Functions for traversing isogeny trees acoording to strategy. Key type 'A' is
//
// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
// for public key generation.
func traverseTreePublicKeyA(curve *ProjectiveCurveParameters, xR, phiP, phiQ, phiR *ProjectivePoint, pub *PublicKey) {
var points = make([]ProjectivePoint, 0, 8)
var indices = make([]int, 0, 8)
var i, sidx int
var op = CurveOperations{Params: pub.params}
cparam := op.CalcCurveParamsEquiv4(curve)
phi := Newisogeny4(op.Params.Op)
strat := pub.params.A.IsogenyStrategy
stratSz := len(strat)
for j := 1; j <= stratSz; j++ {
for i <= stratSz-j {
points = append(points, *xR)
indices = append(indices, i)
k := strat[sidx]
sidx++
op.Pow2k(xR, &cparam, 2*k)
i += int(k)
}
cparam = phi.GenerateCurve(xR)
for k := 0; k < len(points); k++ {
points[k] = phi.EvaluatePoint(&points[k])
}
*phiP = phi.EvaluatePoint(phiP)
*phiQ = phi.EvaluatePoint(phiQ)
*phiR = phi.EvaluatePoint(phiR)
// pop xR from points
*xR, points = points[len(points)-1], points[:len(points)-1]
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
}
}
// Traverses isogeny tree in order to compute xR needed
// for public key generation.
func traverseTreeSharedKeyA(curve *ProjectiveCurveParameters, xR *ProjectivePoint, pub *PublicKey) {
var points = make([]ProjectivePoint, 0, 8)
var indices = make([]int, 0, 8)
var i, sidx int
var op = CurveOperations{Params: pub.params}
cparam := op.CalcCurveParamsEquiv4(curve)
phi := Newisogeny4(op.Params.Op)
strat := pub.params.A.IsogenyStrategy
stratSz := len(strat)
for j := 1; j <= stratSz; j++ {
for i <= stratSz-j {
points = append(points, *xR)
indices = append(indices, i)
k := strat[sidx]
sidx++
op.Pow2k(xR, &cparam, 2*k)
i += int(k)
}
cparam = phi.GenerateCurve(xR)
for k := 0; k < len(points); k++ {
points[k] = phi.EvaluatePoint(&points[k])
}
// pop xR from points
*xR, points = points[len(points)-1], points[:len(points)-1]
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
}
}
// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
// for public key generation.
func traverseTreePublicKeyB(curve *ProjectiveCurveParameters, xR, phiP, phiQ, phiR *ProjectivePoint, pub *PublicKey) {
var points = make([]ProjectivePoint, 0, 8)
var indices = make([]int, 0, 8)
var i, sidx int
var op = CurveOperations{Params: pub.params}
cparam := op.CalcCurveParamsEquiv3(curve)
phi := Newisogeny3(op.Params.Op)
strat := pub.params.B.IsogenyStrategy
stratSz := len(strat)
for j := 1; j <= stratSz; j++ {
for i <= stratSz-j {
points = append(points, *xR)
indices = append(indices, i)
k := strat[sidx]
sidx++
op.Pow3k(xR, &cparam, k)
i += int(k)
}
cparam = phi.GenerateCurve(xR)
for k := 0; k < len(points); k++ {
points[k] = phi.EvaluatePoint(&points[k])
}
*phiP = phi.EvaluatePoint(phiP)
*phiQ = phi.EvaluatePoint(phiQ)
*phiR = phi.EvaluatePoint(phiR)
// pop xR from points
*xR, points = points[len(points)-1], points[:len(points)-1]
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
}
}
// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
// for public key generation.
func traverseTreeSharedKeyB(curve *ProjectiveCurveParameters, xR *ProjectivePoint, pub *PublicKey) {
var points = make([]ProjectivePoint, 0, 8)
var indices = make([]int, 0, 8)
var i, sidx int
var op = CurveOperations{Params: pub.params}
cparam := op.CalcCurveParamsEquiv3(curve)
phi := Newisogeny3(op.Params.Op)
strat := pub.params.B.IsogenyStrategy
stratSz := len(strat)
for j := 1; j <= stratSz; j++ {
for i <= stratSz-j {
points = append(points, *xR)
indices = append(indices, i)
k := strat[sidx]
sidx++
op.Pow3k(xR, &cparam, k)
i += int(k)
}
cparam = phi.GenerateCurve(xR)
for k := 0; k < len(points); k++ {
points[k] = phi.EvaluatePoint(&points[k])
}
// pop xR from points
*xR, points = points[len(points)-1], points[:len(points)-1]
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
}
}
// Generate a public key in the 2-torsion group
func publicKeyGenA(prv *PrivateKey) (pub *PublicKey) {
var xPA, xQA, xRA ProjectivePoint
var xPB, xQB, xRB, xR ProjectivePoint
var invZP, invZQ, invZR Fp2Element
var tmp ProjectiveCurveParameters
pub = NewPublicKey(prv.params.Id, KeyVariant_SIDH_A)
var op = CurveOperations{Params: pub.params}
var phi = Newisogeny4(op.Params.Op)
// Load points for A
xPA = ProjectivePoint{X: prv.params.A.Affine_P, Z: prv.params.OneFp2}
xQA = ProjectivePoint{X: prv.params.A.Affine_Q, Z: prv.params.OneFp2}
xRA = ProjectivePoint{X: prv.params.A.Affine_R, Z: prv.params.OneFp2}
// Load points for B
xRB = ProjectivePoint{X: prv.params.B.Affine_R, Z: prv.params.OneFp2}
xQB = ProjectivePoint{X: prv.params.B.Affine_Q, Z: prv.params.OneFp2}
xPB = ProjectivePoint{X: prv.params.B.Affine_P, Z: prv.params.OneFp2}
// Find isogeny kernel
tmp.C = pub.params.OneFp2
xR = op.ScalarMul3Pt(&tmp, &xPA, &xQA, &xRA, prv.params.A.SecretBitLen, prv.Scalar)
// Reset params object and travers isogeny tree
tmp.C = pub.params.OneFp2
tmp.A.Zeroize()
traverseTreePublicKeyA(&tmp, &xR, &xPB, &xQB, &xRB, pub)
// Secret isogeny
phi.GenerateCurve(&xR)
xPA = phi.EvaluatePoint(&xPB)
xQA = phi.EvaluatePoint(&xQB)
xRA = phi.EvaluatePoint(&xRB)
op.Fp2Batch3Inv(&xPA.Z, &xQA.Z, &xRA.Z, &invZP, &invZQ, &invZR)
op.Params.Op.Mul(&pub.affine_xP, &xPA.X, &invZP)
op.Params.Op.Mul(&pub.affine_xQ, &xQA.X, &invZQ)
op.Params.Op.Mul(&pub.affine_xQmP, &xRA.X, &invZR)
return
}
// Generate a public key in the 3-torsion group
func publicKeyGenB(prv *PrivateKey) (pub *PublicKey) {
var xPB, xQB, xRB, xR ProjectivePoint
var xPA, xQA, xRA ProjectivePoint
var invZP, invZQ, invZR Fp2Element
var tmp ProjectiveCurveParameters
pub = NewPublicKey(prv.params.Id, prv.keyVariant)
var op = CurveOperations{Params: pub.params}
var phi = Newisogeny3(op.Params.Op)
// Load points for B
xRB = ProjectivePoint{X: prv.params.B.Affine_R, Z: prv.params.OneFp2}
xQB = ProjectivePoint{X: prv.params.B.Affine_Q, Z: prv.params.OneFp2}
xPB = ProjectivePoint{X: prv.params.B.Affine_P, Z: prv.params.OneFp2}
// Load points for A
xPA = ProjectivePoint{X: prv.params.A.Affine_P, Z: prv.params.OneFp2}
xQA = ProjectivePoint{X: prv.params.A.Affine_Q, Z: prv.params.OneFp2}
xRA = ProjectivePoint{X: prv.params.A.Affine_R, Z: prv.params.OneFp2}
tmp.C = pub.params.OneFp2
xR = op.ScalarMul3Pt(&tmp, &xPB, &xQB, &xRB, prv.params.B.SecretBitLen, prv.Scalar)
tmp.C = pub.params.OneFp2
tmp.A.Zeroize()
traverseTreePublicKeyB(&tmp, &xR, &xPA, &xQA, &xRA, pub)
phi.GenerateCurve(&xR)
xPB = phi.EvaluatePoint(&xPA)
xQB = phi.EvaluatePoint(&xQA)
xRB = phi.EvaluatePoint(&xRA)
op.Fp2Batch3Inv(&xPB.Z, &xQB.Z, &xRB.Z, &invZP, &invZQ, &invZR)
op.Params.Op.Mul(&pub.affine_xP, &xPB.X, &invZP)
op.Params.Op.Mul(&pub.affine_xQ, &xQB.X, &invZQ)
op.Params.Op.Mul(&pub.affine_xQmP, &xRB.X, &invZR)
return
}
// -----------------------------------------------------------------------------
// Key agreement functions
//
// Establishing shared keys in in 2-torsion group
func deriveSecretA(prv *PrivateKey, pub *PublicKey) []byte {
var sharedSecret = make([]byte, pub.params.SharedSecretSize)
var cparam ProjectiveCurveParameters
var xP, xQ, xQmP ProjectivePoint
var xR ProjectivePoint
var op = CurveOperations{Params: prv.params}
var phi = Newisogeny4(op.Params.Op)
// Recover curve coefficients
cparam.C = pub.params.OneFp2
op.RecoverCoordinateA(&cparam, &pub.affine_xP, &pub.affine_xQ, &pub.affine_xQmP)
// Find kernel of the morphism
xP = ProjectivePoint{X: pub.affine_xP, Z: pub.params.OneFp2}
xQ = ProjectivePoint{X: pub.affine_xQ, Z: pub.params.OneFp2}
xQmP = ProjectivePoint{X: pub.affine_xQmP, Z: pub.params.OneFp2}
xR = op.ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, pub.params.A.SecretBitLen, prv.Scalar)
// Traverse isogeny tree
traverseTreeSharedKeyA(&cparam, &xR, pub)
// Calculate j-invariant on isogeneus curve
c := phi.GenerateCurve(&xR)
op.RecoverCurveCoefficients4(&cparam, &c)
op.Jinvariant(&cparam, sharedSecret)
return sharedSecret
}
// Establishing shared keys in in 3-torsion group
func deriveSecretB(prv *PrivateKey, pub *PublicKey) []byte {
var sharedSecret = make([]byte, pub.params.SharedSecretSize)
var xP, xQ, xQmP ProjectivePoint
var xR ProjectivePoint
var cparam ProjectiveCurveParameters
var op = CurveOperations{Params: prv.params}
var phi = Newisogeny3(op.Params.Op)
// Recover curve coefficients
cparam.C = pub.params.OneFp2
op.RecoverCoordinateA(&cparam, &pub.affine_xP, &pub.affine_xQ, &pub.affine_xQmP)
// Find kernel of the morphism
xP = ProjectivePoint{X: pub.affine_xP, Z: pub.params.OneFp2}
xQ = ProjectivePoint{X: pub.affine_xQ, Z: pub.params.OneFp2}
xQmP = ProjectivePoint{X: pub.affine_xQmP, Z: pub.params.OneFp2}
xR = op.ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, pub.params.B.SecretBitLen, prv.Scalar)
// Traverse isogeny tree
traverseTreeSharedKeyB(&cparam, &xR, pub)
// Calculate j-invariant on isogeneus curve
c := phi.GenerateCurve(&xR)
op.RecoverCurveCoefficients3(&cparam, &c)
op.Jinvariant(&cparam, sharedSecret)
return sharedSecret
}

View File

@ -1,44 +0,0 @@
# Changelog
## v0.10.0 (2018-08-28)
- Add support for QUIC 44, drop support for QUIC 42.
## v0.9.0 (2018-08-15)
- Add a `quic.Config` option for the length of the connection ID (for IETF QUIC).
- Split Session.Close into one method for regular closing and one for closing with an error.
## v0.8.0 (2018-06-26)
- Add support for unidirectional streams (for IETF QUIC).
- Add a `quic.Config` option for the maximum number of incoming streams.
- Add support for QUIC 42 and 43.
- Add dial functions that use a context.
- Multiplex clients on a net.PacketConn, when using Dial(conn).
## v0.7.0 (2018-02-03)
- The lower boundary for packets included in ACKs is now derived, and the value sent in STOP_WAITING frames is ignored.
- Remove `DialNonFWSecure` and `DialAddrNonFWSecure`.
- Expose the `ConnectionState` in the `Session` (experimental API).
- Implement packet pacing.
## v0.6.0 (2017-12-12)
- Add support for QUIC 39, drop support for QUIC 35 - 37
- Added `quic.Config` options for maximal flow control windows
- Add a `quic.Config` option for QUIC versions
- Add a `quic.Config` option to request omission of the connection ID from a server
- Add a `quic.Config` option to configure the source address validation
- Add a `quic.Config` option to configure the handshake timeout
- Add a `quic.Config` option to configure the idle timeout
- Add a `quic.Config` option to configure keep-alive
- Rename the STK to Cookie
- Implement `net.Conn`-style deadlines for streams
- Remove the `tls.Config` from the `quic.Config`. The `tls.Config` must now be passed to the `Dial` and `Listen` functions as a separate parameter. See the [Godoc](https://godoc.org/github.com/lucas-clemente/quic-go) for details.
- Changed the log level environment variable to only accept strings ("DEBUG", "INFO", "ERROR"), see [the wiki](https://github.com/lucas-clemente/quic-go/wiki/Logging) for more details.
- Rename the `h2quic.QuicRoundTripper` to `h2quic.RoundTripper`
- Changed `h2quic.Server.Serve()` to accept a `net.PacketConn`
- Drop support for Go 1.7 and 1.8.
- Various bugfixes

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2016 the quic-go authors & Google, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,68 +0,0 @@
# A QUIC implementation in pure Go
<img src="docs/quic.png" width=303 height=124>
[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/lucas-clemente/quic-go)
[![Travis Build Status](https://img.shields.io/travis/lucas-clemente/quic-go/master.svg?style=flat-square&label=Travis+build)](https://travis-ci.org/lucas-clemente/quic-go)
[![CircleCI Build Status](https://img.shields.io/circleci/project/github/lucas-clemente/quic-go.svg?style=flat-square&label=CircleCI+build)](https://circleci.com/gh/lucas-clemente/quic-go)
[![Windows Build Status](https://img.shields.io/appveyor/ci/lucas-clemente/quic-go/master.svg?style=flat-square&label=windows+build)](https://ci.appveyor.com/project/lucas-clemente/quic-go/branch/master)
[![Code Coverage](https://img.shields.io/codecov/c/github/lucas-clemente/quic-go/master.svg?style=flat-square)](https://codecov.io/gh/lucas-clemente/quic-go/)
quic-go is an implementation of the [QUIC](https://en.wikipedia.org/wiki/QUIC) protocol in Go. It roughly implements the [IETF QUIC draft](https://github.com/quicwg/base-drafts), although we don't fully support any of the draft versions at the moment.
## Version compatibility
Since quic-go is under active development, there's no guarantee that two builds of different commits are interoperable. The QUIC version used in the *master* branch is just a placeholder, and should not be considered stable.
If you want to use quic-go as a library in other projects, please consider using a [tagged release](https://github.com/lucas-clemente/quic-go/releases). These releases expose [experimental QUIC versions](https://github.com/quicwg/base-drafts/wiki/QUIC-Versions), which are guaranteed to be stable.
## Google QUIC
quic-go used to support both the QUIC versions supported by Google Chrome and QUIC as deployed on Google's servers, as well as IETF QUIC. Due to the divergence of the two protocols, we decided to not support both versions any more.
The *master* branch **only** supports IETF QUIC. For Google QUIC support, please refer to the [gquic branch](https://github.com/lucas-clemente/quic-go/tree/gquic).
## Guides
We currently support Go 1.9+.
Installing and updating dependencies:
go get -t -u ./...
Running tests:
go test ./...
### HTTP mapping
We're currently not implementing the HTTP mapping as described in the [QUIC over HTTP draft](https://quicwg.org/base-drafts/draft-ietf-quic-http.html). The HTTP mapping here is a leftover from Google QUIC.
### QUIC without HTTP/2
Take a look at [this echo example](example/echo/echo.go).
## Usage
### As a server
See the [example server](example/main.go). Starting a QUIC server is very similar to the standard lib http in go:
```go
http.Handle("/", http.FileServer(http.Dir(wwwDir)))
h2quic.ListenAndServeQUIC("localhost:4242", "/path/to/cert/chain.pem", "/path/to/privkey.pem", nil)
```
### As a client
See the [example client](example/client/main.go). Use a `h2quic.RoundTripper` as a `Transport` in a `http.Client`.
```go
http.Client{
Transport: &h2quic.RoundTripper{},
}
```
## Contributing
We are always happy to welcome new contributors! We have a number of self-contained issues that are suitable for first-time contributors, they are tagged with [help wanted](https://github.com/lucas-clemente/quic-go/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22). If you have any questions, please feel free to reach out by opening an issue or leaving a comment.

Some files were not shown because too many files have changed in this diff Show More