mirror of https://github.com/v2ray/v2ray-core
Merge branch 'master' of https://github.com/v2fly/v2ray-core into v2fly-master
commit
98911dc9f3
|
@ -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
|
||||
|
|
|
@ -15,6 +15,7 @@ on:
|
|||
|
||||
jobs:
|
||||
analyze:
|
||||
if: github.repository != 'v2ray/v2ray-core'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
|
@ -8,6 +8,7 @@ on:
|
|||
|
||||
jobs:
|
||||
coverage:
|
||||
if: github.repository != 'v2ray/v2ray-core'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go 1.x
|
||||
|
|
|
@ -13,6 +13,7 @@ on:
|
|||
|
||||
jobs:
|
||||
lint:
|
||||
if: github.repository != 'v2ray/v2ray-core'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go 1.x
|
||||
|
|
|
@ -6,6 +6,7 @@ on:
|
|||
|
||||
jobs:
|
||||
sign:
|
||||
if: github.repository != 'v2ray/v2ray-core'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout default branch
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -17,6 +17,7 @@ on:
|
|||
|
||||
jobs:
|
||||
test:
|
||||
if: github.repository != 'v2ray/v2ray-core'
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
|
|
|
@ -6,6 +6,7 @@ on:
|
|||
|
||||
jobs:
|
||||
update:
|
||||
if: github.repository == 'v2fly/v2ray-core'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout codebase
|
||||
|
|
|
@ -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"]
|
||||
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -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
|
||||
|
|
34
README.md
34
README.md
|
@ -3,19 +3,21 @@
|
|||
***
|
||||
|
||||
# Project V
|
||||

|
||||
[![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)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
package commander
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ option java_multiple_files = true;
|
|||
|
||||
message SessionConfig {
|
||||
reserved 1;
|
||||
|
||||
}
|
||||
|
||||
message Config {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
package dispatcher
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
package dispatcher
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
package command
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
package log
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
package command
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package inbound
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package outbound
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -19,7 +19,6 @@ message Control {
|
|||
message BridgeConfig {
|
||||
string tag = 1;
|
||||
string domain = 2;
|
||||
|
||||
}
|
||||
|
||||
message PortalConfig {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
package reverse
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
package router
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
package command
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
|
@ -31,8 +31,7 @@ message QueryStatsResponse {
|
|||
repeated Stat stat = 1;
|
||||
}
|
||||
|
||||
message SysStatsRequest {
|
||||
}
|
||||
message SysStatsRequest {}
|
||||
|
||||
message SysStatsResponse {
|
||||
uint32 NumGoroutine = 1;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, "}")
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
package mux
|
||||
|
||||
//go:generate errorgen
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
22
config.pb.go
22
config.pb.go
|
@ -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"`
|
||||
|
|
22
config.proto
22
config.proto
|
@ -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;
|
||||
|
|
5
core.go
5
core.go
|
@ -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."
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
// Package generic contains the generic marker types.
|
||||
package generic
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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, ¶ms.C, &t0) // Z2p = C24 * t0
|
||||
op.Mul(x, z, &t1) // X2p = Z2p * t1
|
||||
op.Sub(&t1, &t1, &t0) // t1 = t1 - t0
|
||||
op.Mul(&t0, ¶ms.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, ¶ms.A) // t5 = t3 * A24+
|
||||
op.Mul(&t3, &t3, &t5) // t3 = t5 * t3
|
||||
op.Mul(&t6, &t2, ¶ms.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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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},
|
||||
}
|
|
@ -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
|
@ -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)
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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},
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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.
|
|
@ -1,68 +0,0 @@
|
|||
# A QUIC implementation in pure Go
|
||||
|
||||
<img src="docs/quic.png" width=303 height=124>
|
||||
|
||||
[](https://godoc.org/github.com/lucas-clemente/quic-go)
|
||||
[](https://travis-ci.org/lucas-clemente/quic-go)
|
||||
[](https://circleci.com/gh/lucas-clemente/quic-go)
|
||||
[](https://ci.appveyor.com/project/lucas-clemente/quic-go/branch/master)
|
||||
[](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
Loading…
Reference in New Issue