Add Oblivious DoH support
This commit is contained in:
parent
65e70650dc
commit
e3b1f5b7d0
|
@ -262,7 +262,11 @@ func StartServer(
|
|||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
errC <- runDNSProxyServer(c, dnsReadySignal, shutdownC, generalLogger)
|
||||
if c.IsSet("proxy-dns-odoh") {
|
||||
errC <- runDNSProxyServer(c, dnsReadySignal, shutdownC, generalLogger, true)
|
||||
} else {
|
||||
errC <- runDNSProxyServer(c, dnsReadySignal, shutdownC, generalLogger, false)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
close(dnsReadySignal)
|
||||
|
@ -1015,6 +1019,30 @@ func configureProxyDNSFlags(shouldHide bool) []cli.Flag {
|
|||
EnvVars: []string{"TUNNEL_DNS_BOOTSTRAP"},
|
||||
Hidden: shouldHide,
|
||||
}),
|
||||
altsrc.NewBoolFlag(&cli.BoolFlag{
|
||||
Name: "proxy-dns-odoh",
|
||||
Usage: "Runs an Oblivious DNS over HTTPS client.",
|
||||
EnvVars: []string{"TUNNEL_DNS_ODOH"},
|
||||
Hidden: shouldHide,
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: "proxy-dns-odoh-target",
|
||||
Usage: "ODoH target URL",
|
||||
Value: "https://1.1.1.1/dns-query",
|
||||
EnvVars: []string{"TUNNEL_DNS_ODOH_TARGET"},
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: "proxy-dns-odoh-proxy",
|
||||
Usage: "ODoH proxy URL",
|
||||
Value: "https://odoh1.surfdomeinen.nl/proxy",
|
||||
EnvVars: []string{"TUNNEL_DNS_ODOH_PROXY"},
|
||||
}),
|
||||
altsrc.NewBoolFlag(&cli.BoolFlag{
|
||||
Name: "proxy-dns-odoh-useproxy",
|
||||
Usage: "Set flag to enable proxy usage",
|
||||
Value: false,
|
||||
EnvVars: []string{"TUNNEL_DNS_ODOH_USE_PROXY"},
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,22 +9,56 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func runDNSProxyServer(c *cli.Context, dnsReadySignal, shutdownC chan struct{}, logger logger.Service) error {
|
||||
func runDNSProxyServer(c *cli.Context, dnsReadySignal, shutdownC chan struct{}, logger logger.Service, odoh bool) error {
|
||||
port := c.Int("proxy-dns-port")
|
||||
if port <= 0 || port > 65535 {
|
||||
return errors.New("The 'proxy-dns-port' must be a valid port number in <1, 65535> range.")
|
||||
}
|
||||
listener, err := tunneldns.CreateListener(c.String("proxy-dns-address"), uint16(port), c.StringSlice("proxy-dns-upstream"), c.StringSlice("proxy-dns-bootstrap"), logger)
|
||||
var listener *tunneldns.Listener
|
||||
var err error
|
||||
if odoh {
|
||||
listener, err = tunneldns.CreateObliviousDNSListener(
|
||||
c.String("proxy-dns-address"),
|
||||
uint16(port),
|
||||
c.String("proxy-dns-odoh-target"),
|
||||
c.String("proxy-dns-odoh-proxy"),
|
||||
c.Bool("proxy-dns-odoh-useproxy"),
|
||||
logger,
|
||||
)
|
||||
} else {
|
||||
listener, err = tunneldns.CreateListener(
|
||||
c.String("proxy-dns-address"),
|
||||
uint16(port),
|
||||
c.StringSlice("proxy-dns-upstream"),
|
||||
c.StringSlice("proxy-dns-bootstrap"),
|
||||
logger,
|
||||
)
|
||||
}
|
||||
|
||||
// Update odohconfig
|
||||
go listener.UpdateOdohConfig()
|
||||
|
||||
if err != nil {
|
||||
close(dnsReadySignal)
|
||||
listener.Stop()
|
||||
return errors.Wrap(err, "Cannot create the DNS over HTTPS proxy server")
|
||||
if odoh {
|
||||
return errors.Wrap(err, "Cannot create the Oblivious DNS over HTTPS proxy server")
|
||||
} else {
|
||||
return errors.Wrap(err, "Cannot create the DNS over HTTPS proxy server")
|
||||
}
|
||||
}
|
||||
|
||||
err = listener.Start(dnsReadySignal)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot start the DNS over HTTPS proxy server")
|
||||
if odoh {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot start the Oblivious DNS over HTTPS proxy server")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot start the DNS over HTTPS proxy server")
|
||||
}
|
||||
}
|
||||
|
||||
<-shutdownC
|
||||
listener.Stop()
|
||||
return nil
|
||||
|
|
7
go.mod
7
go.mod
|
@ -11,11 +11,11 @@ require (
|
|||
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 // indirect
|
||||
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93
|
||||
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc
|
||||
github.com/cloudflare/odoh-go v0.1.3
|
||||
github.com/coredns/coredns v1.7.0
|
||||
github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0
|
||||
github.com/equinox-io/equinox v1.2.0 // indirect
|
||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
|
||||
github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9 // indirect
|
||||
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434
|
||||
|
@ -42,7 +42,7 @@ require (
|
|||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/lib/pq v1.2.0
|
||||
github.com/mattn/go-sqlite3 v1.11.0
|
||||
github.com/miekg/dns v1.1.31
|
||||
github.com/miekg/dns v1.1.32
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
|
@ -51,9 +51,8 @@ require (
|
|||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||
github.com/prometheus/client_golang v1.7.1
|
||||
github.com/prometheus/common v0.13.0 // indirect
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
||||
github.com/rivo/tview v0.0.0-20200712113419-c65badfc3d92
|
||||
github.com/stretchr/testify v1.6.0
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/urfave/cli/v2 v2.2.0
|
||||
github.com/xo/dburl v0.0.0-20191005012637-293c3298d6c0
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
||||
|
|
87
go.sum
87
go.sum
|
@ -12,6 +12,7 @@ cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bP
|
|||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
|
@ -32,38 +33,50 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
|||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
git.schwanenlied.me/yawning/x448.git v0.0.0-20170617130356-01b048fb03d6 h1:w8IZgCntCe0RuBJp+dENSMwEBl/k8saTgJ5hPca5IWw=
|
||||
git.schwanenlied.me/yawning/x448.git v0.0.0-20170617130356-01b048fb03d6/go.mod h1:wQaGCqEu44ykB17jZHCevrgSVl3KJnwQBObUtrKU4uU=
|
||||
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v40.6.0+incompatible h1:ULjp/a/UsBfnZcl45jjywhcBKex/k/A1cG9s9NapLFw=
|
||||
github.com/Azure/azure-sdk-for-go v40.6.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
|
||||
github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
|
||||
github.com/Azure/go-autorest/autorest v0.10.2 h1:NuSF3gXetiHyUbVdneJMEVyPUYAe5wh+aN08JYAf1tI=
|
||||
github.com/Azure/go-autorest/autorest v0.10.2/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM=
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwpKNMpV+/FTWjwEbuPD495Tk=
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM=
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U=
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U=
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw=
|
||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=
|
||||
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||
github.com/Azure/go-autorest/autorest/to v0.2.0 h1:nQOZzFCudTh+TvquAtCRjM01VEYx85e9qbwt5ncW4L8=
|
||||
github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc=
|
||||
github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
|
||||
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
|
||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||
github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/DataDog/datadog-go v3.5.0+incompatible h1:AShr9cqkF+taHjyQgcBcQUt/ZNK+iPq4ROaZwSX5c/U=
|
||||
github.com/DataDog/datadog-go v3.5.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/DataDog/zstd v1.3.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
|
@ -109,12 +122,15 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
|
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||
github.com/caddyserver/caddy v1.0.5 h1:5B1Hs0UF2x2tggr2X9jL2qOZtDXbIWQb9YLbmlxHSuM=
|
||||
github.com/caddyserver/caddy v1.0.5/go.mod h1:AnFHB+/MrgRC+mJAvuAgQ38ePzw+wKeW0wzENpdQQKY=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
|
||||
github.com/cenkalti/backoff/v4 v4.0.2 h1:JIufpQLbh4DkbQoii76ItQIUFzevQSqOLZca4eamEDs=
|
||||
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
|
@ -126,15 +142,23 @@ github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wX
|
|||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cisco/go-hpke v0.0.0-20201023221920-2866d2aa0603 h1:dszdCFyug261XPbbU9YQA+8CnpPJm1svHDeCHd8vhRI=
|
||||
github.com/cisco/go-hpke v0.0.0-20201023221920-2866d2aa0603/go.mod h1:AyK7f6CWiLAvOFmAyCEF5xDN51zS6PIZgj3Qq7hla1Y=
|
||||
github.com/cisco/go-tls-syntax v0.0.0-20200617162716-46b0cfb76b9b h1:Ves2turKTX7zruivAcUOQg155xggcbv3suVdbKCBQNM=
|
||||
github.com/cisco/go-tls-syntax v0.0.0-20200617162716-46b0cfb76b9b/go.mod h1:0AZAV7lYvynZQ5ErHlGMKH+4QYMyNCFd+AiL9MlrCYA=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93 h1:QrGfkZDnMxcWHaYDdB7CmqS9i26OAnUj/xcus/abYkY=
|
||||
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93/go.mod h1:QiTe66jFdP7cUKMCCf/WrvDyYdtdmdZfVcdoLbzaKVY=
|
||||
github.com/cloudflare/circl v1.0.0 h1:64b6pyfCFbYm623ncIkYGNZaOcmIbyd+CjyMi2L9vdI=
|
||||
github.com/cloudflare/circl v1.0.0/go.mod h1:MhjB3NEEhJbTOdLLq964NIUisXDxaE1WkQPUxtgZXiY=
|
||||
github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
|
||||
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc h1:Dvk3ySBsOm5EviLx6VCyILnafPcQinXGP5jbTdHUJgE=
|
||||
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc/go.mod h1:HlgKKR8V5a1wroIDDIz3/A+T+9Janfq+7n1P5sEFdi0=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||
github.com/cloudflare/odoh-go v0.1.3 h1:kI0ANqbcLfKZHZOJ6myyEMWReQTy6ZOybSBFpg2yTsM=
|
||||
github.com/cloudflare/odoh-go v0.1.3/go.mod h1:+8PrCWF56ioFtPx7VyhT8fL/IM6cJtPNh9IecQ1EIxg=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
|
@ -146,6 +170,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
|||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/license-bill-of-materials v0.0.0-20190913234955-13baff47494e/go.mod h1:4xMOusJ7xxc84WclVxKT8+lNfGYDwojOUC2OQNCwcj4=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
|
@ -160,10 +185,13 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0 h1:epsH3lb7KVbXHYk7LYGN5EiE0MxcevHU85CKITJ0wUY=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
||||
github.com/dnstap/golang-dnstap v0.2.0 h1:+NrmP4mkaTeKYV7xJ5FXpUxRn0RpcgoQcsOCTS8WQPk=
|
||||
github.com/dnstap/golang-dnstap v0.2.0/go.mod h1:s1PfVYYVmTMgCSPtho4LKBDecEHJWtiVDPNv78Z985U=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
|
@ -179,16 +207,19 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
|||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/equinox-io/equinox v1.2.0 h1:bBS7Ou+Y7Jwgmy8TWSYxEh85WctuFn7FPlgbUzX4DBA=
|
||||
github.com/equinox-io/equinox v1.2.0/go.mod h1:6s3HJB0PYUNgs0mxmI8fHdfVl3TQ25ieA/PVfr+eyVo=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE=
|
||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
||||
github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9 h1:wWke/RUCl7VRjQhwPlR/v0glZXNYzBHdNUzf/Am2Nmg=
|
||||
github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9/go.mod h1:uPmAp6Sws4L7+Q/OokbWDAK1ibXYhB3PXFP1kol5hPg=
|
||||
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434 h1:mOp33BLbcbJ8fvTAmZacbBiOASfxN+MLcLxymZCIrGE=
|
||||
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434/go.mod h1:KigFdumBXUPSwzLDbeuzyt0elrL7+CP7TKuhrhT4bcU=
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
|
||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y=
|
||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
||||
github.com/farsightsec/golang-framestream v0.0.0-20190425193708-fa4b164d59b8 h1:/iPdQppoAsTfML+yqFSq2EBChiEMnRkh5WvhFgtWwcU=
|
||||
github.com/farsightsec/golang-framestream v0.0.0-20190425193708-fa4b164d59b8/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
|
@ -196,6 +227,7 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjr
|
|||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
github.com/frankban/quicktest v1.10.0 h1:Gfh+GAJZOAoKZsIZeZbdn2JF10kN1XHNvjsvQK8gVkE=
|
||||
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
|
@ -245,6 +277,7 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG
|
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=
|
||||
|
@ -255,6 +288,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
|
|||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
|
@ -289,9 +323,11 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
|
@ -308,11 +344,14 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.1.0 h1:rVsPeBmXbYv4If/cumu1AzZPwV58q433hvONV1UEZoI=
|
||||
github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gophercloud/gophercloud v0.9.0 h1:eJHQQFguQRv2FatH2d2VXH2ueTe2XzjgjwFjFS7SGcs=
|
||||
github.com/gophercloud/gophercloud v0.9.0/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
|
@ -348,6 +387,7 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA
|
|||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
|
@ -358,9 +398,11 @@ github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmK
|
|||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
|
||||
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/infobloxopen/go-trees v0.0.0-20190313150506-2af4e13f9062 h1:d3VSuNcgTCn21dNMm8g412Fck/XWFmMj4nJhhHT7ZZ0=
|
||||
github.com/infobloxopen/go-trees v0.0.0-20190313150506-2af4e13f9062/go.mod h1:PcNJqIlcX/dj3DTG/+QQnRvSgTMG6CLpRMjWcv4+J6w=
|
||||
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
|
@ -392,13 +434,16 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
|
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kshvakov/clickhouse v1.3.11 h1:dtzTJY0fCA+MWkLyuKZaNPkmSwdX4gh8+Klic9NB1Lw=
|
||||
github.com/kshvakov/clickhouse v1.3.11/go.mod h1:/SVBAcqF3u7rxQ9sTWCZwf8jzzvxiZGeQvtmSF2BBEc=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
|
||||
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||
|
@ -435,8 +480,8 @@ github.com/mholt/certmagic v0.8.3/go.mod h1:91uJzK5K8IWtYQqTi5R2tsxV1pCde+wdGfaR
|
|||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
|
||||
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.32 h1:MDaYYzWOYscpvDOEgPMT1c1mebCZmIdxZI/J161OdJU=
|
||||
github.com/miekg/dns v1.1.32/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
|
@ -468,6 +513,7 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
|
|||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw=
|
||||
github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
|
||||
|
@ -484,6 +530,7 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
|
|||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
|
@ -491,9 +538,11 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt
|
|||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.3.5/go.mod h1:uVHyebswE1cCXr2A73cRM2frx5ld1RJUCJkFNZ90ZiI=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5 h1:ZCnq+JUrvXcDVhX/xRolRBZifmabN1HcS1wrPSvxhrU=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/openzipkin/zipkin-go v0.2.2 h1:nY8Hti+WKaP0cRsSeQ026wU03QsM762XBeCXBb9NAWI=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
||||
|
@ -502,9 +551,11 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
|
|||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI=
|
||||
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -543,7 +594,6 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
|
|||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
|
||||
|
@ -551,7 +601,6 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
|
|||
github.com/prometheus/prometheus v2.5.0+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
|
||||
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
|
||||
github.com/rivo/tview v0.0.0-20200712113419-c65badfc3d92 h1:rqaqSUdaW+OBbjnsrOoiaJv43mSRARuvsAuirmdxu7E=
|
||||
github.com/rivo/tview v0.0.0-20200712113419-c65badfc3d92/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84=
|
||||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
||||
|
@ -582,6 +631,7 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd
|
|||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
|
@ -592,10 +642,10 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
|
||||
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
|
||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
|
||||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY=
|
||||
|
@ -617,6 +667,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.etcd.io/etcd v0.5.0-alpha.5.0.20200306183522-221f0cc107cb h1:TcJ8iNja1CH/h/3QcsydKL5krb0MIPjMJLYgzClNaSQ=
|
||||
go.etcd.io/etcd v0.5.0-alpha.5.0.20200306183522-221f0cc107cb/go.mod h1:VZB9Yx4s43MHItytoe8jcvaEFEgF2QzHDZGfQ/XQjvQ=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
|
@ -624,17 +675,21 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
|||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
||||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
@ -765,6 +820,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -811,6 +867,7 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb
|
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -865,6 +922,7 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
|
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
|
@ -883,6 +941,7 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
|||
google.golang.org/api v0.26.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
@ -956,11 +1015,13 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/DataDog/dd-trace-go.v1 v1.24.1 h1:CGQIcKZxAsFtMTUiXw0TxBWwj+l+b2bS2V8l1bIsfk4=
|
||||
gopkg.in/DataDog/dd-trace-go.v1 v1.24.1/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/coreos/go-oidc.v2 v2.1.0 h1:E8PjVFdj/SLDKB0hvb70KTbMbYVHjqztiQdSkIg8E+I=
|
||||
|
@ -969,6 +1030,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
@ -1002,21 +1064,28 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.18.3 h1:2AJaUQdgUZLoDZHrun21PW2Nx9+ll6cUzvn3IKhSIn0=
|
||||
k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA=
|
||||
k8s.io/apimachinery v0.18.3 h1:pOGcbVAhxADgUYnjS08EFXs9QMl8qaH5U4fr5LGUrSk=
|
||||
k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko=
|
||||
k8s.io/client-go v0.18.3 h1:QaJzz92tsN67oorwzmoB0a9r9ZVHuD5ryjbCKP0U22k=
|
||||
k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||
zombiezen.com/go/capnproto2 v2.18.0+incompatible h1:mwfXZniffG5mXokQGHUJWGnqIBggoPfT/CEwon9Yess=
|
||||
|
|
|
@ -12,30 +12,47 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
odoh "github.com/cloudflare/odoh-go"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTimeout = 5 * time.Second
|
||||
defaultTimeout = 10 * time.Second
|
||||
odohConfigDuration = 3600 * time.Second
|
||||
targetHostname = "odoh.cloudflare-dns.com."
|
||||
)
|
||||
|
||||
// ObliviousDoHCtx maintains info needed for the ODoH service
|
||||
type ObliviousDoHCtx struct {
|
||||
useproxy bool
|
||||
target *url.URL
|
||||
queryCtx *odoh.QueryContext
|
||||
}
|
||||
|
||||
// UpstreamHTTPS is the upstream implementation for DNS over HTTPS service
|
||||
type UpstreamHTTPS struct {
|
||||
client *http.Client
|
||||
endpoint *url.URL
|
||||
bootstraps []string
|
||||
odoh *ObliviousDoHCtx
|
||||
logger logger.Service
|
||||
}
|
||||
|
||||
// NewUpstreamHTTPS creates a new DNS over HTTPS upstream from endpoint
|
||||
func NewUpstreamHTTPS(endpoint string, bootstraps []string, logger logger.Service) (Upstream, error) {
|
||||
func NewUpstreamHTTPS(endpoint string, bootstraps []string, odohCtx *ObliviousDoHCtx, logger logger.Service) (Upstream, error) {
|
||||
u, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &UpstreamHTTPS{client: configureClient(u.Hostname()), endpoint: u, bootstraps: bootstraps, logger: logger}, nil
|
||||
return &UpstreamHTTPS{
|
||||
client: configureClient(u.Hostname()),
|
||||
endpoint: u,
|
||||
bootstraps: bootstraps,
|
||||
odoh: odohCtx,
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Exchange provides an implementation for the Upstream interface
|
||||
|
@ -45,35 +62,95 @@ func (u *UpstreamHTTPS) Exchange(ctx context.Context, query *dns.Msg) (*dns.Msg,
|
|||
return nil, errors.Wrap(err, "failed to pack DNS query")
|
||||
}
|
||||
|
||||
if len(query.Question) > 0 && query.Question[0].Name == fmt.Sprintf("%s.", u.endpoint.Hostname()) {
|
||||
for _, bootstrap := range u.bootstraps {
|
||||
endpoint, client, err := configureBootstrap(bootstrap)
|
||||
if err != nil {
|
||||
u.logger.Errorf("failed to configure boostrap upstream %s: %s", bootstrap, err)
|
||||
continue
|
||||
if u.odoh == nil {
|
||||
if len(query.Question) > 0 && query.Question[0].Name == fmt.Sprintf("%s.", u.endpoint.Hostname()) {
|
||||
for _, bootstrap := range u.bootstraps {
|
||||
endpoint, client, err := configureBootstrap(bootstrap)
|
||||
if err != nil {
|
||||
u.logger.Errorf("failed to configure boostrap upstream %s: %s", bootstrap, err)
|
||||
continue
|
||||
}
|
||||
msg, err := exchange(queryBuf, query.Id, endpoint, client, u.odoh, u.logger)
|
||||
if err != nil {
|
||||
u.logger.Errorf("failed to connect to a boostrap upstream %s: %s", bootstrap, err)
|
||||
continue
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
msg, err := exchange(queryBuf, query.Id, endpoint, client, u.logger)
|
||||
if err != nil {
|
||||
u.logger.Errorf("failed to connect to a boostrap upstream %s: %s", bootstrap, err)
|
||||
continue
|
||||
}
|
||||
return msg, nil
|
||||
return nil, fmt.Errorf("failed to reach any bootstrap upstream: %v", u.bootstraps)
|
||||
}
|
||||
return nil, fmt.Errorf("failed to reach any bootstrap upstream: %v", u.bootstraps)
|
||||
} else {
|
||||
odohQuery, queryCtx, err := createOdohQuery(queryBuf, OdohConfig)
|
||||
if err != nil {
|
||||
u.logger.Errorf("failed to create oblivious query: %s", err)
|
||||
}
|
||||
queryBuf = odohQuery
|
||||
u.odoh.queryCtx = &queryCtx
|
||||
}
|
||||
return exchange(queryBuf, query.Id, u.endpoint, u.client, u.odoh, u.logger)
|
||||
|
||||
return exchange(queryBuf, query.Id, u.endpoint, u.client, u.logger)
|
||||
}
|
||||
|
||||
func exchange(msg []byte, queryID uint16, endpoint *url.URL, client *http.Client, logger logger.Service) (*dns.Msg, error) {
|
||||
func createOdohQuery(dnsMessage []byte, publicKey odoh.ObliviousDoHConfigContents) ([]byte, odoh.QueryContext, error) {
|
||||
odohQuery := odoh.CreateObliviousDNSQuery(dnsMessage, 0)
|
||||
encryptedMessage, queryContext, err := publicKey.EncryptQuery(odohQuery)
|
||||
if err != nil {
|
||||
return nil, odoh.QueryContext{}, err
|
||||
}
|
||||
return encryptedMessage.Marshal(), queryContext, nil
|
||||
}
|
||||
|
||||
// FetchObliviousDoHConfig fetches `odohconfig` by querying the target server for HTTPS records.
|
||||
func FetchObliviousDoHConfig(client *http.Client, msg []byte, dohResolver *url.URL) (*odoh.ObliviousDoHConfigs, error) {
|
||||
buf, err := exchangeWireformat(msg, dohResolver, client, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := &dns.Msg{}
|
||||
if err := response.Unpack(buf); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unpack HTTPS DNS response from body")
|
||||
}
|
||||
|
||||
// extracts `odohconfig` from the https record
|
||||
for _, answer := range response.Answer {
|
||||
httpsResponse, ok := answer.(*dns.HTTPS)
|
||||
if ok {
|
||||
for _, value := range httpsResponse.Value {
|
||||
if value.Key() == 32769 {
|
||||
parameter, ok := value.(*dns.SVCBLocal)
|
||||
if ok {
|
||||
odohConfigs, err := odoh.UnmarshalObliviousDoHConfigs(parameter.Data)
|
||||
if err == nil {
|
||||
return &odohConfigs, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func exchange(msg []byte, queryID uint16, endpoint *url.URL, client *http.Client, odohCtx *ObliviousDoHCtx, logger logger.Service) (*dns.Msg, error) {
|
||||
// No content negotiation for now, use DNS wire format
|
||||
buf, backendErr := exchangeWireformat(msg, endpoint, client)
|
||||
buf, backendErr := exchangeWireformat(msg, endpoint, client, odohCtx)
|
||||
if backendErr == nil {
|
||||
response := &dns.Msg{}
|
||||
if odohCtx != nil {
|
||||
odohQueryResponse, err := odoh.UnmarshalDNSMessage(buf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to deserialize ObliviousDoHMessage from response")
|
||||
}
|
||||
buf, err = odohCtx.queryCtx.OpenAnswer(odohQueryResponse)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to decrypt encrypted response")
|
||||
}
|
||||
}
|
||||
if err := response.Unpack(buf); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unpack DNS response from body")
|
||||
}
|
||||
|
||||
response.Id = queryID
|
||||
return response, nil
|
||||
}
|
||||
|
@ -83,16 +160,28 @@ func exchange(msg []byte, queryID uint16, endpoint *url.URL, client *http.Client
|
|||
}
|
||||
|
||||
// Perform message exchange with the default UDP wireformat defined in current draft
|
||||
// https://datatracker.ietf.org/doc/draft-ietf-doh-dns-over-https
|
||||
func exchangeWireformat(msg []byte, endpoint *url.URL, client *http.Client) ([]byte, error) {
|
||||
// https://datatracker.ietf.org/doc/draft-ietf-doh-dns-over-https for DoH and
|
||||
// https://tools.ietf.org/html/draft-pauly-dprive-oblivious-doh-03 for ODoH
|
||||
func exchangeWireformat(msg []byte, endpoint *url.URL, client *http.Client, odoh *ObliviousDoHCtx) ([]byte, error) {
|
||||
req, err := http.NewRequest("POST", endpoint.String(), bytes.NewBuffer(msg))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create an HTTPS request")
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/dns-message")
|
||||
if odoh != nil {
|
||||
req.Header.Add("Content-Type", "application/oblivious-dns-message")
|
||||
req.Header.Add("Accept", "application/oblivious-dns-message")
|
||||
req.Header.Add("Cache-Control", "no-cache, no-store")
|
||||
if odoh.useproxy {
|
||||
queries := req.URL.Query()
|
||||
queries.Add("targethost", odoh.target.Hostname())
|
||||
queries.Add("targetpath", "/dns-query")
|
||||
req.URL.RawQuery = queries.Encode()
|
||||
}
|
||||
} else {
|
||||
req.Header.Add("Content-Type", "application/dns-message")
|
||||
}
|
||||
req.Host = endpoint.Host
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to perform an HTTPS request")
|
||||
|
|
|
@ -2,15 +2,20 @@ package tunneldns
|
|||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/metrics"
|
||||
odoh "github.com/cloudflare/odoh-go"
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
|
@ -26,6 +31,12 @@ type Listener struct {
|
|||
logger logger.Service
|
||||
}
|
||||
|
||||
const (
|
||||
dohResolver = "https://1.1.1.1/dns-query"
|
||||
)
|
||||
|
||||
var OdohConfig odoh.ObliviousDoHConfigContents
|
||||
|
||||
func Command(hidden bool) *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "proxy-dns",
|
||||
|
@ -63,6 +74,33 @@ func Command(hidden bool) *cli.Command {
|
|||
EnvVars: []string{"TUNNEL_DNS_BOOTSTRAP"},
|
||||
},
|
||||
},
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "odoh",
|
||||
Action: cliutil.ErrorHandler(RunOdoh),
|
||||
Usage: "Runs an Oblivious DNS over HTTPS client.",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "target",
|
||||
Usage: "ODoH target URL",
|
||||
Value: "https://1.1.1.1/dns-query",
|
||||
EnvVars: []string{"TUNNEL_DNS_ODOH_TARGET"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "proxy",
|
||||
Usage: "ODoH proxy URL",
|
||||
Value: "https://odoh1.surfdomeinen.nl/proxy",
|
||||
EnvVars: []string{"TUNNEL_DNS_ODOH_PROXY"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "useproxy",
|
||||
Usage: "Set flag to enable proxy usage",
|
||||
Value: false,
|
||||
EnvVars: []string{"TUNNEL_DNS_ODOH_USE_PROXY"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ArgsUsage: " ", // can't be the empty string or we get the default output
|
||||
Hidden: hidden,
|
||||
}
|
||||
|
@ -82,7 +120,13 @@ func Run(c *cli.Context) error {
|
|||
|
||||
go metrics.ServeMetrics(metricsListener, nil, nil, logger)
|
||||
|
||||
listener, err := CreateListener(c.String("address"), uint16(c.Uint("port")), c.StringSlice("upstream"), c.StringSlice("bootstrap"), logger)
|
||||
listener, err := CreateListener(
|
||||
c.String("address"),
|
||||
uint16(c.Uint("port")),
|
||||
c.StringSlice("upstream"),
|
||||
c.StringSlice("bootstrap"),
|
||||
logger,
|
||||
)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to create the listeners: %s", err)
|
||||
return err
|
||||
|
@ -111,6 +155,59 @@ func Run(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// RunOdoh implements a foreground runner
|
||||
func RunOdoh(c *cli.Context) error {
|
||||
logger, err := logger.CreateLoggerFromContext(c, logger.EnableTerminalLog)
|
||||
if err != nil {
|
||||
return cliutil.PrintLoggerSetupError("error setting up logger", err)
|
||||
}
|
||||
|
||||
metricsListener, err := net.Listen("tcp", c.String("metrics"))
|
||||
if err != nil {
|
||||
logger.Fatalf("Failed to open the metrics listener: %s", err)
|
||||
}
|
||||
|
||||
go metrics.ServeMetrics(metricsListener, nil, nil, logger)
|
||||
|
||||
listener, err := CreateObliviousDNSListener(
|
||||
c.String("address"),
|
||||
uint16(c.Uint("port")),
|
||||
c.String("target"),
|
||||
c.String("proxy"),
|
||||
c.Bool("useproxy"),
|
||||
logger,
|
||||
)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to create the listeners: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Update odohconfig
|
||||
go listener.UpdateOdohConfig()
|
||||
|
||||
// Try to start the server
|
||||
readySignal := make(chan struct{})
|
||||
err = listener.Start(readySignal)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to start the listeners: %s", err)
|
||||
return listener.Stop()
|
||||
}
|
||||
<-readySignal
|
||||
|
||||
// Wait for signal
|
||||
signals := make(chan os.Signal, 10)
|
||||
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
|
||||
defer signal.Stop(signals)
|
||||
<-signals
|
||||
|
||||
// Shut down server
|
||||
err = listener.Stop()
|
||||
if err != nil {
|
||||
logger.Errorf("failed to stop: %s", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a CoreDNS server plugin from configuration
|
||||
func createConfig(address string, port uint16, p plugin.Handler) *dnsserver.Config {
|
||||
c := &dnsserver.Config{
|
||||
|
@ -127,7 +224,8 @@ func createConfig(address string, port uint16, p plugin.Handler) *dnsserver.Conf
|
|||
// Start blocks for serving requests
|
||||
func (l *Listener) Start(readySignal chan struct{}) error {
|
||||
defer close(readySignal)
|
||||
l.logger.Infof("Starting DNS over HTTPS proxy server on: %s", l.server.Address())
|
||||
|
||||
l.logger.Infof("Starting DNS proxy server on: %s", l.server.Address())
|
||||
|
||||
// Start UDP listener
|
||||
if udp, err := l.server.ListenPacket(); err == nil {
|
||||
|
@ -153,6 +251,26 @@ func (l *Listener) Start(readySignal chan struct{}) error {
|
|||
return errors.Wrap(err, "failed to create a TCP listener")
|
||||
}
|
||||
|
||||
// UpdateOdohConfig periodically updates odoh configs
|
||||
// Currently supports `odoh.cloudflare-dns.com.`.
|
||||
func (l *Listener) UpdateOdohConfig() {
|
||||
l.logger.Infof("Starting Oblivious DoH key updates")
|
||||
dohResolver, _ := url.Parse(dohResolver)
|
||||
client := http.Client{}
|
||||
dnsQuery := new(dns.Msg)
|
||||
dnsQuery.SetQuestion(targetHostname, dns.TypeHTTPS)
|
||||
dnsQuery.RecursionDesired = true
|
||||
packedDNSQuery, _ := dnsQuery.Pack()
|
||||
for {
|
||||
configs, err := FetchObliviousDoHConfig(&client, packedDNSQuery, dohResolver)
|
||||
if err != nil {
|
||||
l.logger.Errorf("odoh config not updated with err ", err)
|
||||
}
|
||||
OdohConfig = configs.Configs[0].Contents
|
||||
time.Sleep(odohConfigDuration)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop signals server shutdown and blocks until completed
|
||||
func (l *Listener) Stop() error {
|
||||
if err := l.server.Stop(); err != nil {
|
||||
|
@ -169,17 +287,48 @@ func CreateListener(address string, port uint16, upstreams []string, bootstraps
|
|||
upstreamList := make([]Upstream, 0)
|
||||
for _, url := range upstreams {
|
||||
logger.Infof("Adding DNS upstream - url: %s", url)
|
||||
upstream, err := NewUpstreamHTTPS(url, bootstraps, logger)
|
||||
upstream, err := NewUpstreamHTTPS(url, bootstraps, nil, logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create HTTPS upstream")
|
||||
}
|
||||
upstreamList = append(upstreamList, upstream)
|
||||
}
|
||||
|
||||
return buildListenerFromUpstream(upstreamList, address, port, logger)
|
||||
}
|
||||
|
||||
// CreateObliviousDNSListener configures the server and bound sockets
|
||||
func CreateObliviousDNSListener(address string, port uint16, target string, proxy string, useproxy bool, logger logger.Service) (*Listener, error) {
|
||||
logger.Infof("Adding Oblivious DoH target - url: %s", target)
|
||||
var upstream Upstream
|
||||
var err error
|
||||
targetURL, err := url.Parse(target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
odohCtx := ObliviousDoHCtx{
|
||||
useproxy: useproxy,
|
||||
target: targetURL,
|
||||
}
|
||||
if useproxy {
|
||||
logger.Infof("Adding Oblivious DoH proxy - url: %s", proxy)
|
||||
upstream, err = NewUpstreamHTTPS(proxy, nil, &odohCtx, logger)
|
||||
} else {
|
||||
logger.Infof("No Oblivious DoH proxy is set")
|
||||
upstream, err = NewUpstreamHTTPS(target, nil, &odohCtx, logger)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create HTTPS upstream")
|
||||
}
|
||||
|
||||
return buildListenerFromUpstream([]Upstream{upstream}, address, port, logger)
|
||||
}
|
||||
|
||||
func buildListenerFromUpstream(upstreams []Upstream, address string, port uint16, logger logger.Service) (*Listener, error) {
|
||||
// Create a local cache with HTTPS proxy plugin
|
||||
chain := cache.New()
|
||||
chain.Next = ProxyPlugin{
|
||||
Upstreams: upstreamList,
|
||||
Upstreams: upstreams,
|
||||
}
|
||||
|
||||
// Format an endpoint
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2015 Cryptography Research, Inc.
|
||||
Copyright (c) 2015 Yawning Angel.
|
||||
|
||||
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.
|
|
@ -0,0 +1,13 @@
|
|||
### x448 - curve448 ECDH
|
||||
#### Yawning Angel (yawning at schwanenlied dot me)
|
||||
|
||||
A straight forward port of Michael Hamburg's x448 code to Go lang.
|
||||
|
||||
See: https://www.rfc-editor.org/rfc/rfc7748.txt
|
||||
|
||||
If you're familiar with how to use golang.org/x/crypto/curve25519, you will be
|
||||
right at home with using x448, since the functions are the same. Generate a
|
||||
random secret key, ScalarBaseMult() to get the public key, etc etc etc.
|
||||
|
||||
Both routines return 0 on success, -1 on failure which MUST be checked, and
|
||||
the handshake aborted on failure.
|
|
@ -0,0 +1,114 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2014-2015 Cryptography Research, Inc.
|
||||
// Copyright (c) 2015 Yawning Angel.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// Package x448 provides an implementation of scalar multiplication on the
|
||||
// elliptic curve known as curve448.
|
||||
//
|
||||
// See https://tools.ietf.org/html/draft-irtf-cfrg-curves-11
|
||||
package x448 // import "git.schwanenlied.me/yawning/x448.git"
|
||||
|
||||
const (
|
||||
x448Bytes = 56
|
||||
edwardsD = -39081
|
||||
)
|
||||
|
||||
var basePoint = [56]byte{
|
||||
5, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
}
|
||||
|
||||
func ScalarMult(out, scalar, base *[56]byte) int {
|
||||
var x1, x2, z2, x3, z3, t1, t2 gf
|
||||
x1.deser(base)
|
||||
x2.cpy(&one)
|
||||
z2.cpy(&zero)
|
||||
x3.cpy(&x1)
|
||||
z3.cpy(&one)
|
||||
|
||||
var swap limbUint
|
||||
|
||||
for t := int(448 - 1); t >= 0; t-- {
|
||||
sb := scalar[t/8]
|
||||
|
||||
// Scalar conditioning.
|
||||
if t/8 == 0 {
|
||||
sb &= 0xFC
|
||||
} else if t/8 == x448Bytes-1 {
|
||||
sb |= 0x80
|
||||
}
|
||||
|
||||
kT := (limbUint)((sb >> ((uint)(t) % 8)) & 1)
|
||||
kT = -kT // Set to all 0s or all 1s
|
||||
|
||||
swap ^= kT
|
||||
x2.condSwap(&x3, swap)
|
||||
z2.condSwap(&z3, swap)
|
||||
swap = kT
|
||||
|
||||
t1.add(&x2, &z2) // A = x2 + z2
|
||||
t2.sub(&x2, &z2) // B = x2 - z2
|
||||
z2.sub(&x3, &z3) // D = x3 - z3
|
||||
x2.mul(&t1, &z2) // DA
|
||||
z2.add(&z3, &x3) // C = x3 + z3
|
||||
x3.mul(&t2, &z2) // CB
|
||||
z3.sub(&x2, &x3) // DA-CB
|
||||
z2.sqr(&z3) // (DA-CB)^2
|
||||
z3.mul(&x1, &z2) // z3 = x1(DA-CB)^2
|
||||
z2.add(&x2, &x3) // (DA+CB)
|
||||
x3.sqr(&z2) // x3 = (DA+CB)^2
|
||||
|
||||
z2.sqr(&t1) // AA = A^2
|
||||
t1.sqr(&t2) // BB = B^2
|
||||
x2.mul(&z2, &t1) // x2 = AA*BB
|
||||
t2.sub(&z2, &t1) // E = AA-BB
|
||||
|
||||
t1.mlw(&t2, -edwardsD) // E*-d = a24*E
|
||||
t1.add(&t1, &z2) // AA + a24*E
|
||||
z2.mul(&t2, &t1) // z2 = E(AA+a24*E)
|
||||
}
|
||||
|
||||
// Finish
|
||||
x2.condSwap(&x3, swap)
|
||||
z2.condSwap(&x3, swap)
|
||||
z2.inv(&z2)
|
||||
x1.mul(&x2, &z2)
|
||||
x1.ser(out)
|
||||
|
||||
// As with X25519, both sides MUST check, without leaking extra
|
||||
// information about the value of K, whether the resulting shared K is
|
||||
// the all-zero value and abort if so.
|
||||
var nz limbSint
|
||||
for _, v := range out {
|
||||
nz |= (limbSint)(v)
|
||||
}
|
||||
nz = (nz - 1) >> 8 // 0 = succ, -1 = fail
|
||||
|
||||
// return value: 0 = succ, -1 = fail
|
||||
return (int)(nz)
|
||||
}
|
||||
|
||||
func ScalarBaseMult(out, scalar *[56]byte) int {
|
||||
return ScalarMult(out, scalar, &basePoint)
|
||||
}
|
|
@ -0,0 +1,778 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2014-2015 Cryptography Research, Inc.
|
||||
// Copyright (c) 2015 Yawning Angel.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package x448
|
||||
|
||||
// This should really use 64 bit limbs, but Go is fucking retarded and doesn't
|
||||
// have __(u)int128_t, so the 32 bit code it is, at a hefty performance
|
||||
// penalty. Fuck my life, I'm going to have to bust out PeachPy to get this
|
||||
// to go fast aren't I.
|
||||
|
||||
const (
|
||||
wBits = 32
|
||||
lBits = (wBits * 7 / 8)
|
||||
x448Limbs = (448 / lBits)
|
||||
lMask = (1 << lBits) - 1
|
||||
)
|
||||
|
||||
type limbUint uint32
|
||||
type limbSint int32
|
||||
|
||||
type gf struct {
|
||||
limb [x448Limbs]uint32
|
||||
}
|
||||
|
||||
var zero = gf{[x448Limbs]uint32{0}}
|
||||
var one = gf{[x448Limbs]uint32{1}}
|
||||
var p = gf{[x448Limbs]uint32{
|
||||
lMask, lMask, lMask, lMask, lMask, lMask, lMask, lMask,
|
||||
lMask - 1, lMask, lMask, lMask, lMask, lMask, lMask, lMask,
|
||||
}}
|
||||
|
||||
// cpy copies x = y.
|
||||
func (x *gf) cpy(y *gf) {
|
||||
// for i, v := range y.limb {
|
||||
// x.limb[i] = v
|
||||
// }
|
||||
|
||||
copy(x.limb[:], y.limb[:])
|
||||
}
|
||||
|
||||
// mul multiplies c = a * b. (PERF)
|
||||
func (c *gf) mul(a, b *gf) {
|
||||
var aa gf
|
||||
aa.cpy(a)
|
||||
|
||||
//
|
||||
// This is *by far* the most CPU intesive routine in the code.
|
||||
//
|
||||
|
||||
// var accum [x448Limbs]uint64
|
||||
// for i, bv := range b.limb {
|
||||
// for j, aav := range aa.limb {
|
||||
// accum[(i+j)%x448Limbs] += (uint64)(bv) * (uint64)(aav)
|
||||
// }
|
||||
// aa.limb[(x448Limbs-1-i)^(x448Limbs/2)] += aa.limb[x448Limbs-1-i]
|
||||
// }
|
||||
|
||||
// So fucking stupid that this is actually a fairly massive gain.
|
||||
var accum0, accum1, accum2, accum3, accum4, accum5, accum6, accum7, accum8, accum9, accum10, accum11, accum12, accum13, accum14, accum15 uint64
|
||||
var bv uint64
|
||||
|
||||
bv = (uint64)(b.limb[0])
|
||||
accum0 += bv * (uint64)(aa.limb[0])
|
||||
accum1 += bv * (uint64)(aa.limb[1])
|
||||
accum2 += bv * (uint64)(aa.limb[2])
|
||||
accum3 += bv * (uint64)(aa.limb[3])
|
||||
accum4 += bv * (uint64)(aa.limb[4])
|
||||
accum5 += bv * (uint64)(aa.limb[5])
|
||||
accum6 += bv * (uint64)(aa.limb[6])
|
||||
accum7 += bv * (uint64)(aa.limb[7])
|
||||
accum8 += bv * (uint64)(aa.limb[8])
|
||||
accum9 += bv * (uint64)(aa.limb[9])
|
||||
accum10 += bv * (uint64)(aa.limb[10])
|
||||
accum11 += bv * (uint64)(aa.limb[11])
|
||||
accum12 += bv * (uint64)(aa.limb[12])
|
||||
accum13 += bv * (uint64)(aa.limb[13])
|
||||
accum14 += bv * (uint64)(aa.limb[14])
|
||||
accum15 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-0)^(x448Limbs/2)] += aa.limb[x448Limbs-1-0]
|
||||
|
||||
bv = (uint64)(b.limb[1])
|
||||
accum1 += bv * (uint64)(aa.limb[0])
|
||||
accum2 += bv * (uint64)(aa.limb[1])
|
||||
accum3 += bv * (uint64)(aa.limb[2])
|
||||
accum4 += bv * (uint64)(aa.limb[3])
|
||||
accum5 += bv * (uint64)(aa.limb[4])
|
||||
accum6 += bv * (uint64)(aa.limb[5])
|
||||
accum7 += bv * (uint64)(aa.limb[6])
|
||||
accum8 += bv * (uint64)(aa.limb[7])
|
||||
accum9 += bv * (uint64)(aa.limb[8])
|
||||
accum10 += bv * (uint64)(aa.limb[9])
|
||||
accum11 += bv * (uint64)(aa.limb[10])
|
||||
accum12 += bv * (uint64)(aa.limb[11])
|
||||
accum13 += bv * (uint64)(aa.limb[12])
|
||||
accum14 += bv * (uint64)(aa.limb[13])
|
||||
accum15 += bv * (uint64)(aa.limb[14])
|
||||
accum0 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-1)^(x448Limbs/2)] += aa.limb[x448Limbs-1-1]
|
||||
|
||||
bv = (uint64)(b.limb[2])
|
||||
accum2 += bv * (uint64)(aa.limb[0])
|
||||
accum3 += bv * (uint64)(aa.limb[1])
|
||||
accum4 += bv * (uint64)(aa.limb[2])
|
||||
accum5 += bv * (uint64)(aa.limb[3])
|
||||
accum6 += bv * (uint64)(aa.limb[4])
|
||||
accum7 += bv * (uint64)(aa.limb[5])
|
||||
accum8 += bv * (uint64)(aa.limb[6])
|
||||
accum9 += bv * (uint64)(aa.limb[7])
|
||||
accum10 += bv * (uint64)(aa.limb[8])
|
||||
accum11 += bv * (uint64)(aa.limb[9])
|
||||
accum12 += bv * (uint64)(aa.limb[10])
|
||||
accum13 += bv * (uint64)(aa.limb[11])
|
||||
accum14 += bv * (uint64)(aa.limb[12])
|
||||
accum15 += bv * (uint64)(aa.limb[13])
|
||||
accum0 += bv * (uint64)(aa.limb[14])
|
||||
accum1 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-2)^(x448Limbs/2)] += aa.limb[x448Limbs-1-2]
|
||||
|
||||
bv = (uint64)(b.limb[3])
|
||||
accum3 += bv * (uint64)(aa.limb[0])
|
||||
accum4 += bv * (uint64)(aa.limb[1])
|
||||
accum5 += bv * (uint64)(aa.limb[2])
|
||||
accum6 += bv * (uint64)(aa.limb[3])
|
||||
accum7 += bv * (uint64)(aa.limb[4])
|
||||
accum8 += bv * (uint64)(aa.limb[5])
|
||||
accum9 += bv * (uint64)(aa.limb[6])
|
||||
accum10 += bv * (uint64)(aa.limb[7])
|
||||
accum11 += bv * (uint64)(aa.limb[8])
|
||||
accum12 += bv * (uint64)(aa.limb[9])
|
||||
accum13 += bv * (uint64)(aa.limb[10])
|
||||
accum14 += bv * (uint64)(aa.limb[11])
|
||||
accum15 += bv * (uint64)(aa.limb[12])
|
||||
accum0 += bv * (uint64)(aa.limb[13])
|
||||
accum1 += bv * (uint64)(aa.limb[14])
|
||||
accum2 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-3)^(x448Limbs/2)] += aa.limb[x448Limbs-1-3]
|
||||
|
||||
bv = (uint64)(b.limb[4])
|
||||
accum4 += bv * (uint64)(aa.limb[0])
|
||||
accum5 += bv * (uint64)(aa.limb[1])
|
||||
accum6 += bv * (uint64)(aa.limb[2])
|
||||
accum7 += bv * (uint64)(aa.limb[3])
|
||||
accum8 += bv * (uint64)(aa.limb[4])
|
||||
accum9 += bv * (uint64)(aa.limb[5])
|
||||
accum10 += bv * (uint64)(aa.limb[6])
|
||||
accum11 += bv * (uint64)(aa.limb[7])
|
||||
accum12 += bv * (uint64)(aa.limb[8])
|
||||
accum13 += bv * (uint64)(aa.limb[9])
|
||||
accum14 += bv * (uint64)(aa.limb[10])
|
||||
accum15 += bv * (uint64)(aa.limb[11])
|
||||
accum0 += bv * (uint64)(aa.limb[12])
|
||||
accum1 += bv * (uint64)(aa.limb[13])
|
||||
accum2 += bv * (uint64)(aa.limb[14])
|
||||
accum3 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-4)^(x448Limbs/2)] += aa.limb[x448Limbs-1-4]
|
||||
|
||||
bv = (uint64)(b.limb[5])
|
||||
accum5 += bv * (uint64)(aa.limb[0])
|
||||
accum6 += bv * (uint64)(aa.limb[1])
|
||||
accum7 += bv * (uint64)(aa.limb[2])
|
||||
accum8 += bv * (uint64)(aa.limb[3])
|
||||
accum9 += bv * (uint64)(aa.limb[4])
|
||||
accum10 += bv * (uint64)(aa.limb[5])
|
||||
accum11 += bv * (uint64)(aa.limb[6])
|
||||
accum12 += bv * (uint64)(aa.limb[7])
|
||||
accum13 += bv * (uint64)(aa.limb[8])
|
||||
accum14 += bv * (uint64)(aa.limb[9])
|
||||
accum15 += bv * (uint64)(aa.limb[10])
|
||||
accum0 += bv * (uint64)(aa.limb[11])
|
||||
accum1 += bv * (uint64)(aa.limb[12])
|
||||
accum2 += bv * (uint64)(aa.limb[13])
|
||||
accum3 += bv * (uint64)(aa.limb[14])
|
||||
accum4 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-5)^(x448Limbs/2)] += aa.limb[x448Limbs-1-5]
|
||||
|
||||
bv = (uint64)(b.limb[6])
|
||||
accum6 += bv * (uint64)(aa.limb[0])
|
||||
accum7 += bv * (uint64)(aa.limb[1])
|
||||
accum8 += bv * (uint64)(aa.limb[2])
|
||||
accum9 += bv * (uint64)(aa.limb[3])
|
||||
accum10 += bv * (uint64)(aa.limb[4])
|
||||
accum11 += bv * (uint64)(aa.limb[5])
|
||||
accum12 += bv * (uint64)(aa.limb[6])
|
||||
accum13 += bv * (uint64)(aa.limb[7])
|
||||
accum14 += bv * (uint64)(aa.limb[8])
|
||||
accum15 += bv * (uint64)(aa.limb[9])
|
||||
accum0 += bv * (uint64)(aa.limb[10])
|
||||
accum1 += bv * (uint64)(aa.limb[11])
|
||||
accum2 += bv * (uint64)(aa.limb[12])
|
||||
accum3 += bv * (uint64)(aa.limb[13])
|
||||
accum4 += bv * (uint64)(aa.limb[14])
|
||||
accum5 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-6)^(x448Limbs/2)] += aa.limb[x448Limbs-1-6]
|
||||
|
||||
bv = (uint64)(b.limb[7])
|
||||
accum7 += bv * (uint64)(aa.limb[0])
|
||||
accum8 += bv * (uint64)(aa.limb[1])
|
||||
accum9 += bv * (uint64)(aa.limb[2])
|
||||
accum10 += bv * (uint64)(aa.limb[3])
|
||||
accum11 += bv * (uint64)(aa.limb[4])
|
||||
accum12 += bv * (uint64)(aa.limb[5])
|
||||
accum13 += bv * (uint64)(aa.limb[6])
|
||||
accum14 += bv * (uint64)(aa.limb[7])
|
||||
accum15 += bv * (uint64)(aa.limb[8])
|
||||
accum0 += bv * (uint64)(aa.limb[9])
|
||||
accum1 += bv * (uint64)(aa.limb[10])
|
||||
accum2 += bv * (uint64)(aa.limb[11])
|
||||
accum3 += bv * (uint64)(aa.limb[12])
|
||||
accum4 += bv * (uint64)(aa.limb[13])
|
||||
accum5 += bv * (uint64)(aa.limb[14])
|
||||
accum6 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-7)^(x448Limbs/2)] += aa.limb[x448Limbs-1-7]
|
||||
|
||||
bv = (uint64)(b.limb[8])
|
||||
accum8 += bv * (uint64)(aa.limb[0])
|
||||
accum9 += bv * (uint64)(aa.limb[1])
|
||||
accum10 += bv * (uint64)(aa.limb[2])
|
||||
accum11 += bv * (uint64)(aa.limb[3])
|
||||
accum12 += bv * (uint64)(aa.limb[4])
|
||||
accum13 += bv * (uint64)(aa.limb[5])
|
||||
accum14 += bv * (uint64)(aa.limb[6])
|
||||
accum15 += bv * (uint64)(aa.limb[7])
|
||||
accum0 += bv * (uint64)(aa.limb[8])
|
||||
accum1 += bv * (uint64)(aa.limb[9])
|
||||
accum2 += bv * (uint64)(aa.limb[10])
|
||||
accum3 += bv * (uint64)(aa.limb[11])
|
||||
accum4 += bv * (uint64)(aa.limb[12])
|
||||
accum5 += bv * (uint64)(aa.limb[13])
|
||||
accum6 += bv * (uint64)(aa.limb[14])
|
||||
accum7 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-8)^(x448Limbs/2)] += aa.limb[x448Limbs-1-8]
|
||||
|
||||
bv = (uint64)(b.limb[9])
|
||||
accum9 += bv * (uint64)(aa.limb[0])
|
||||
accum10 += bv * (uint64)(aa.limb[1])
|
||||
accum11 += bv * (uint64)(aa.limb[2])
|
||||
accum12 += bv * (uint64)(aa.limb[3])
|
||||
accum13 += bv * (uint64)(aa.limb[4])
|
||||
accum14 += bv * (uint64)(aa.limb[5])
|
||||
accum15 += bv * (uint64)(aa.limb[6])
|
||||
accum0 += bv * (uint64)(aa.limb[7])
|
||||
accum1 += bv * (uint64)(aa.limb[8])
|
||||
accum2 += bv * (uint64)(aa.limb[9])
|
||||
accum3 += bv * (uint64)(aa.limb[10])
|
||||
accum4 += bv * (uint64)(aa.limb[11])
|
||||
accum5 += bv * (uint64)(aa.limb[12])
|
||||
accum6 += bv * (uint64)(aa.limb[13])
|
||||
accum7 += bv * (uint64)(aa.limb[14])
|
||||
accum8 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-9)^(x448Limbs/2)] += aa.limb[x448Limbs-1-9]
|
||||
|
||||
bv = (uint64)(b.limb[10])
|
||||
accum10 += bv * (uint64)(aa.limb[0])
|
||||
accum11 += bv * (uint64)(aa.limb[1])
|
||||
accum12 += bv * (uint64)(aa.limb[2])
|
||||
accum13 += bv * (uint64)(aa.limb[3])
|
||||
accum14 += bv * (uint64)(aa.limb[4])
|
||||
accum15 += bv * (uint64)(aa.limb[5])
|
||||
accum0 += bv * (uint64)(aa.limb[6])
|
||||
accum1 += bv * (uint64)(aa.limb[7])
|
||||
accum2 += bv * (uint64)(aa.limb[8])
|
||||
accum3 += bv * (uint64)(aa.limb[9])
|
||||
accum4 += bv * (uint64)(aa.limb[10])
|
||||
accum5 += bv * (uint64)(aa.limb[11])
|
||||
accum6 += bv * (uint64)(aa.limb[12])
|
||||
accum7 += bv * (uint64)(aa.limb[13])
|
||||
accum8 += bv * (uint64)(aa.limb[14])
|
||||
accum9 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-10)^(x448Limbs/2)] += aa.limb[x448Limbs-1-10]
|
||||
|
||||
bv = (uint64)(b.limb[11])
|
||||
accum11 += bv * (uint64)(aa.limb[0])
|
||||
accum12 += bv * (uint64)(aa.limb[1])
|
||||
accum13 += bv * (uint64)(aa.limb[2])
|
||||
accum14 += bv * (uint64)(aa.limb[3])
|
||||
accum15 += bv * (uint64)(aa.limb[4])
|
||||
accum0 += bv * (uint64)(aa.limb[5])
|
||||
accum1 += bv * (uint64)(aa.limb[6])
|
||||
accum2 += bv * (uint64)(aa.limb[7])
|
||||
accum3 += bv * (uint64)(aa.limb[8])
|
||||
accum4 += bv * (uint64)(aa.limb[9])
|
||||
accum5 += bv * (uint64)(aa.limb[10])
|
||||
accum6 += bv * (uint64)(aa.limb[11])
|
||||
accum7 += bv * (uint64)(aa.limb[12])
|
||||
accum8 += bv * (uint64)(aa.limb[13])
|
||||
accum9 += bv * (uint64)(aa.limb[14])
|
||||
accum10 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-11)^(x448Limbs/2)] += aa.limb[x448Limbs-1-11]
|
||||
|
||||
bv = (uint64)(b.limb[12])
|
||||
accum12 += bv * (uint64)(aa.limb[0])
|
||||
accum13 += bv * (uint64)(aa.limb[1])
|
||||
accum14 += bv * (uint64)(aa.limb[2])
|
||||
accum15 += bv * (uint64)(aa.limb[3])
|
||||
accum0 += bv * (uint64)(aa.limb[4])
|
||||
accum1 += bv * (uint64)(aa.limb[5])
|
||||
accum2 += bv * (uint64)(aa.limb[6])
|
||||
accum3 += bv * (uint64)(aa.limb[7])
|
||||
accum4 += bv * (uint64)(aa.limb[8])
|
||||
accum5 += bv * (uint64)(aa.limb[9])
|
||||
accum6 += bv * (uint64)(aa.limb[10])
|
||||
accum7 += bv * (uint64)(aa.limb[11])
|
||||
accum8 += bv * (uint64)(aa.limb[12])
|
||||
accum9 += bv * (uint64)(aa.limb[13])
|
||||
accum10 += bv * (uint64)(aa.limb[14])
|
||||
accum11 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-12)^(x448Limbs/2)] += aa.limb[x448Limbs-1-12]
|
||||
|
||||
bv = (uint64)(b.limb[13])
|
||||
accum13 += bv * (uint64)(aa.limb[0])
|
||||
accum14 += bv * (uint64)(aa.limb[1])
|
||||
accum15 += bv * (uint64)(aa.limb[2])
|
||||
accum0 += bv * (uint64)(aa.limb[3])
|
||||
accum1 += bv * (uint64)(aa.limb[4])
|
||||
accum2 += bv * (uint64)(aa.limb[5])
|
||||
accum3 += bv * (uint64)(aa.limb[6])
|
||||
accum4 += bv * (uint64)(aa.limb[7])
|
||||
accum5 += bv * (uint64)(aa.limb[8])
|
||||
accum6 += bv * (uint64)(aa.limb[9])
|
||||
accum7 += bv * (uint64)(aa.limb[10])
|
||||
accum8 += bv * (uint64)(aa.limb[11])
|
||||
accum9 += bv * (uint64)(aa.limb[12])
|
||||
accum10 += bv * (uint64)(aa.limb[13])
|
||||
accum11 += bv * (uint64)(aa.limb[14])
|
||||
accum12 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-13)^(x448Limbs/2)] += aa.limb[x448Limbs-1-13]
|
||||
|
||||
bv = (uint64)(b.limb[14])
|
||||
accum14 += bv * (uint64)(aa.limb[0])
|
||||
accum15 += bv * (uint64)(aa.limb[1])
|
||||
accum0 += bv * (uint64)(aa.limb[2])
|
||||
accum1 += bv * (uint64)(aa.limb[3])
|
||||
accum2 += bv * (uint64)(aa.limb[4])
|
||||
accum3 += bv * (uint64)(aa.limb[5])
|
||||
accum4 += bv * (uint64)(aa.limb[6])
|
||||
accum5 += bv * (uint64)(aa.limb[7])
|
||||
accum6 += bv * (uint64)(aa.limb[8])
|
||||
accum7 += bv * (uint64)(aa.limb[9])
|
||||
accum8 += bv * (uint64)(aa.limb[10])
|
||||
accum9 += bv * (uint64)(aa.limb[11])
|
||||
accum10 += bv * (uint64)(aa.limb[12])
|
||||
accum11 += bv * (uint64)(aa.limb[13])
|
||||
accum12 += bv * (uint64)(aa.limb[14])
|
||||
accum13 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-14)^(x448Limbs/2)] += aa.limb[x448Limbs-1-14]
|
||||
|
||||
bv = (uint64)(b.limb[15])
|
||||
accum15 += bv * (uint64)(aa.limb[0])
|
||||
accum0 += bv * (uint64)(aa.limb[1])
|
||||
accum1 += bv * (uint64)(aa.limb[2])
|
||||
accum2 += bv * (uint64)(aa.limb[3])
|
||||
accum3 += bv * (uint64)(aa.limb[4])
|
||||
accum4 += bv * (uint64)(aa.limb[5])
|
||||
accum5 += bv * (uint64)(aa.limb[6])
|
||||
accum6 += bv * (uint64)(aa.limb[7])
|
||||
accum7 += bv * (uint64)(aa.limb[8])
|
||||
accum8 += bv * (uint64)(aa.limb[9])
|
||||
accum9 += bv * (uint64)(aa.limb[10])
|
||||
accum10 += bv * (uint64)(aa.limb[11])
|
||||
accum11 += bv * (uint64)(aa.limb[12])
|
||||
accum12 += bv * (uint64)(aa.limb[13])
|
||||
accum13 += bv * (uint64)(aa.limb[14])
|
||||
accum14 += bv * (uint64)(aa.limb[15])
|
||||
aa.limb[(x448Limbs-1-15)^(x448Limbs/2)] += aa.limb[x448Limbs-1-15]
|
||||
|
||||
// accum[x448Limbs-1] += accum[x448Limbs-2] >> lBits
|
||||
// accum[x448Limbs-2] &= lMask
|
||||
// accum[x448Limbs/2] += accum[x448Limbs-1] >> lBits
|
||||
accum15 += accum14 >> lBits
|
||||
accum14 &= lMask
|
||||
accum8 += accum15 >> lBits
|
||||
|
||||
// for j := uint(0); j < x448Limbs; j++ {
|
||||
// accum[j] += accum[(j-1)%x448Limbs] >> lBits
|
||||
// accum[(j-1)%x448Limbs] &= lMask
|
||||
// }
|
||||
accum0 += accum15 >> lBits
|
||||
accum15 &= lMask
|
||||
accum1 += accum0 >> lBits
|
||||
accum0 &= lMask
|
||||
accum2 += accum1 >> lBits
|
||||
accum1 &= lMask
|
||||
accum3 += accum2 >> lBits
|
||||
accum2 &= lMask
|
||||
accum4 += accum3 >> lBits
|
||||
accum3 &= lMask
|
||||
accum5 += accum4 >> lBits
|
||||
accum4 &= lMask
|
||||
accum6 += accum5 >> lBits
|
||||
accum5 &= lMask
|
||||
accum7 += accum6 >> lBits
|
||||
accum6 &= lMask
|
||||
accum8 += accum7 >> lBits
|
||||
accum7 &= lMask
|
||||
accum9 += accum8 >> lBits
|
||||
accum8 &= lMask
|
||||
accum10 += accum9 >> lBits
|
||||
accum9 &= lMask
|
||||
accum11 += accum10 >> lBits
|
||||
accum10 &= lMask
|
||||
accum12 += accum11 >> lBits
|
||||
accum11 &= lMask
|
||||
accum13 += accum12 >> lBits
|
||||
accum12 &= lMask
|
||||
accum14 += accum13 >> lBits
|
||||
accum13 &= lMask
|
||||
accum15 += accum14 >> lBits
|
||||
accum14 &= lMask
|
||||
|
||||
// for j, accv := range accum {
|
||||
// c.limb[j] = (uint32)(accv)
|
||||
// }
|
||||
c.limb[0] = (uint32)(accum0)
|
||||
c.limb[1] = (uint32)(accum1)
|
||||
c.limb[2] = (uint32)(accum2)
|
||||
c.limb[3] = (uint32)(accum3)
|
||||
c.limb[4] = (uint32)(accum4)
|
||||
c.limb[5] = (uint32)(accum5)
|
||||
c.limb[6] = (uint32)(accum6)
|
||||
c.limb[7] = (uint32)(accum7)
|
||||
c.limb[8] = (uint32)(accum8)
|
||||
c.limb[9] = (uint32)(accum9)
|
||||
c.limb[10] = (uint32)(accum10)
|
||||
c.limb[11] = (uint32)(accum11)
|
||||
c.limb[12] = (uint32)(accum12)
|
||||
c.limb[13] = (uint32)(accum13)
|
||||
c.limb[14] = (uint32)(accum14)
|
||||
c.limb[15] = (uint32)(accum15)
|
||||
}
|
||||
|
||||
// sqr squares (c = x * x). Just calls multiply. (PERF)
|
||||
func (c *gf) sqr(x *gf) {
|
||||
c.mul(x, x)
|
||||
}
|
||||
|
||||
// isqrt inverse square roots (y = 1/sqrt(x)), using an addition chain.
|
||||
func (y *gf) isqrt(x *gf) {
|
||||
var a, b, c gf
|
||||
c.sqr(x)
|
||||
|
||||
// XXX/Yawning, could unroll, but this is called only once.
|
||||
|
||||
// STEP(b,x,1);
|
||||
b.mul(x, &c)
|
||||
c.cpy(&b)
|
||||
for i := 0; i < 1; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
// STEP(b,x,3);
|
||||
b.mul(x, &c)
|
||||
c.cpy(&b)
|
||||
for i := 0; i < 3; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
//STEP(a,b,3);
|
||||
a.mul(&b, &c)
|
||||
c.cpy(&a)
|
||||
for i := 0; i < 3; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
// STEP(a,b,9);
|
||||
a.mul(&b, &c)
|
||||
c.cpy(&a)
|
||||
for i := 0; i < 9; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
// STEP(b,a,1);
|
||||
b.mul(&a, &c)
|
||||
c.cpy(&b)
|
||||
for i := 0; i < 1; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
// STEP(a,x,18);
|
||||
a.mul(x, &c)
|
||||
c.cpy(&a)
|
||||
for i := 0; i < 18; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
// STEP(a,b,37);
|
||||
a.mul(&b, &c)
|
||||
c.cpy(&a)
|
||||
for i := 0; i < 37; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
// STEP(b,a,37);
|
||||
b.mul(&a, &c)
|
||||
c.cpy(&b)
|
||||
for i := 0; i < 37; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
// STEP(b,a,111);
|
||||
b.mul(&a, &c)
|
||||
c.cpy(&b)
|
||||
for i := 0; i < 111; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
// STEP(a,b,1);
|
||||
a.mul(&b, &c)
|
||||
c.cpy(&a)
|
||||
for i := 0; i < 1; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
// STEP(b,x,223);
|
||||
b.mul(x, &c)
|
||||
c.cpy(&b)
|
||||
for i := 0; i < 223; i++ {
|
||||
c.sqr(&c)
|
||||
}
|
||||
|
||||
y.mul(&a, &c)
|
||||
}
|
||||
|
||||
// inv inverses (y = 1/x).
|
||||
func (y *gf) inv(x *gf) {
|
||||
var z, w gf
|
||||
z.sqr(x) // x^2
|
||||
w.isqrt(&z) // +- 1/sqrt(x^2) = +- 1/x
|
||||
z.sqr(&w) // 1/x^2
|
||||
w.mul(x, &z) // 1/x
|
||||
y.cpy(&w)
|
||||
}
|
||||
|
||||
// reduce weakly reduces mod p
|
||||
func (x *gf) reduce() {
|
||||
x.limb[x448Limbs/2] += x.limb[x448Limbs-1] >> lBits
|
||||
|
||||
// for j := uint(0); j < x448Limbs; j++ {
|
||||
// x.limb[j] += x.limb[(j-1)%x448Limbs] >> lBits
|
||||
// x.limb[(j-1)%x448Limbs] &= lMask
|
||||
// }
|
||||
x.limb[0] += x.limb[15] >> lBits
|
||||
x.limb[15] &= lMask
|
||||
x.limb[1] += x.limb[0] >> lBits
|
||||
x.limb[0] &= lMask
|
||||
x.limb[2] += x.limb[1] >> lBits
|
||||
x.limb[1] &= lMask
|
||||
x.limb[3] += x.limb[2] >> lBits
|
||||
x.limb[2] &= lMask
|
||||
x.limb[4] += x.limb[3] >> lBits
|
||||
x.limb[3] &= lMask
|
||||
x.limb[5] += x.limb[4] >> lBits
|
||||
x.limb[4] &= lMask
|
||||
x.limb[6] += x.limb[5] >> lBits
|
||||
x.limb[5] &= lMask
|
||||
x.limb[7] += x.limb[6] >> lBits
|
||||
x.limb[6] &= lMask
|
||||
x.limb[8] += x.limb[7] >> lBits
|
||||
x.limb[7] &= lMask
|
||||
x.limb[9] += x.limb[8] >> lBits
|
||||
x.limb[8] &= lMask
|
||||
x.limb[10] += x.limb[9] >> lBits
|
||||
x.limb[9] &= lMask
|
||||
x.limb[11] += x.limb[10] >> lBits
|
||||
x.limb[10] &= lMask
|
||||
x.limb[12] += x.limb[11] >> lBits
|
||||
x.limb[11] &= lMask
|
||||
x.limb[13] += x.limb[12] >> lBits
|
||||
x.limb[12] &= lMask
|
||||
x.limb[14] += x.limb[13] >> lBits
|
||||
x.limb[13] &= lMask
|
||||
x.limb[15] += x.limb[14] >> lBits
|
||||
x.limb[14] &= lMask
|
||||
}
|
||||
|
||||
// add adds mod p. Conservatively always weak-reduces. (PERF)
|
||||
func (x *gf) add(y, z *gf) {
|
||||
// for i, yv := range y.limb {
|
||||
// x.limb[i] = yv + z.limb[i]
|
||||
// }
|
||||
x.limb[0] = y.limb[0] + z.limb[0]
|
||||
x.limb[1] = y.limb[1] + z.limb[1]
|
||||
x.limb[2] = y.limb[2] + z.limb[2]
|
||||
x.limb[3] = y.limb[3] + z.limb[3]
|
||||
x.limb[4] = y.limb[4] + z.limb[4]
|
||||
x.limb[5] = y.limb[5] + z.limb[5]
|
||||
x.limb[6] = y.limb[6] + z.limb[6]
|
||||
x.limb[7] = y.limb[7] + z.limb[7]
|
||||
x.limb[8] = y.limb[8] + z.limb[8]
|
||||
x.limb[9] = y.limb[9] + z.limb[9]
|
||||
x.limb[10] = y.limb[10] + z.limb[10]
|
||||
x.limb[11] = y.limb[11] + z.limb[11]
|
||||
x.limb[12] = y.limb[12] + z.limb[12]
|
||||
x.limb[13] = y.limb[13] + z.limb[13]
|
||||
x.limb[14] = y.limb[14] + z.limb[14]
|
||||
x.limb[15] = y.limb[15] + z.limb[15]
|
||||
|
||||
x.reduce()
|
||||
}
|
||||
|
||||
// sub subtracts mod p. Conservatively always weak-reduces. (PERF)
|
||||
func (x *gf) sub(y, z *gf) {
|
||||
// for i, yv := range y.limb {
|
||||
// x.limb[i] = yv - z.limb[i] + 2*p.limb[i]
|
||||
// }
|
||||
x.limb[0] = y.limb[0] - z.limb[0] + 2*lMask
|
||||
x.limb[1] = y.limb[1] - z.limb[1] + 2*lMask
|
||||
x.limb[2] = y.limb[2] - z.limb[2] + 2*lMask
|
||||
x.limb[3] = y.limb[3] - z.limb[3] + 2*lMask
|
||||
x.limb[4] = y.limb[4] - z.limb[4] + 2*lMask
|
||||
x.limb[5] = y.limb[5] - z.limb[5] + 2*lMask
|
||||
x.limb[6] = y.limb[6] - z.limb[6] + 2*lMask
|
||||
x.limb[7] = y.limb[7] - z.limb[7] + 2*lMask
|
||||
x.limb[8] = y.limb[8] - z.limb[8] + 2*(lMask-1)
|
||||
x.limb[9] = y.limb[9] - z.limb[9] + 2*lMask
|
||||
x.limb[10] = y.limb[10] - z.limb[10] + 2*lMask
|
||||
x.limb[11] = y.limb[11] - z.limb[11] + 2*lMask
|
||||
x.limb[12] = y.limb[12] - z.limb[12] + 2*lMask
|
||||
x.limb[13] = y.limb[13] - z.limb[13] + 2*lMask
|
||||
x.limb[14] = y.limb[14] - z.limb[14] + 2*lMask
|
||||
x.limb[15] = y.limb[15] - z.limb[15] + 2*lMask
|
||||
|
||||
x.reduce()
|
||||
}
|
||||
|
||||
// condSwap swaps x and y in constant time.
|
||||
func (x *gf) condSwap(y *gf, swap limbUint) {
|
||||
// for i, xv := range x.limb {
|
||||
// s := (xv ^ y.limb[i]) & (uint32)(swap) // Sort of dumb, oh well.
|
||||
// x.limb[i] ^= s
|
||||
// y.limb[i] ^= s
|
||||
// }
|
||||
|
||||
var s uint32
|
||||
|
||||
s = (x.limb[0] ^ y.limb[0]) & (uint32)(swap)
|
||||
x.limb[0] ^= s
|
||||
y.limb[0] ^= s
|
||||
s = (x.limb[1] ^ y.limb[1]) & (uint32)(swap)
|
||||
x.limb[1] ^= s
|
||||
y.limb[1] ^= s
|
||||
s = (x.limb[2] ^ y.limb[2]) & (uint32)(swap)
|
||||
x.limb[2] ^= s
|
||||
y.limb[2] ^= s
|
||||
s = (x.limb[3] ^ y.limb[3]) & (uint32)(swap)
|
||||
x.limb[3] ^= s
|
||||
y.limb[3] ^= s
|
||||
s = (x.limb[4] ^ y.limb[4]) & (uint32)(swap)
|
||||
x.limb[4] ^= s
|
||||
y.limb[4] ^= s
|
||||
s = (x.limb[5] ^ y.limb[5]) & (uint32)(swap)
|
||||
x.limb[5] ^= s
|
||||
y.limb[5] ^= s
|
||||
s = (x.limb[6] ^ y.limb[6]) & (uint32)(swap)
|
||||
x.limb[6] ^= s
|
||||
y.limb[6] ^= s
|
||||
s = (x.limb[7] ^ y.limb[7]) & (uint32)(swap)
|
||||
x.limb[7] ^= s
|
||||
y.limb[7] ^= s
|
||||
s = (x.limb[8] ^ y.limb[8]) & (uint32)(swap)
|
||||
x.limb[8] ^= s
|
||||
y.limb[8] ^= s
|
||||
s = (x.limb[9] ^ y.limb[9]) & (uint32)(swap)
|
||||
x.limb[9] ^= s
|
||||
y.limb[9] ^= s
|
||||
s = (x.limb[10] ^ y.limb[10]) & (uint32)(swap)
|
||||
x.limb[10] ^= s
|
||||
y.limb[10] ^= s
|
||||
s = (x.limb[11] ^ y.limb[11]) & (uint32)(swap)
|
||||
x.limb[11] ^= s
|
||||
y.limb[11] ^= s
|
||||
s = (x.limb[12] ^ y.limb[12]) & (uint32)(swap)
|
||||
x.limb[12] ^= s
|
||||
y.limb[12] ^= s
|
||||
s = (x.limb[13] ^ y.limb[13]) & (uint32)(swap)
|
||||
x.limb[13] ^= s
|
||||
y.limb[13] ^= s
|
||||
s = (x.limb[14] ^ y.limb[14]) & (uint32)(swap)
|
||||
x.limb[14] ^= s
|
||||
y.limb[14] ^= s
|
||||
s = (x.limb[15] ^ y.limb[15]) & (uint32)(swap)
|
||||
x.limb[15] ^= s
|
||||
y.limb[15] ^= s
|
||||
}
|
||||
|
||||
// mlw multiplies by a signed int. NOT CONSTANT TIME wrt the sign of the int,
|
||||
// but that's ok because it's only ever called with w = -edwardsD. Just uses
|
||||
// a full multiply. (PERF)
|
||||
func (a *gf) mlw(b *gf, w int) {
|
||||
if w > 0 {
|
||||
ww := gf{[x448Limbs]uint32{(uint32)(w)}}
|
||||
a.mul(b, &ww)
|
||||
} else {
|
||||
// This branch is *NEVER* taken with the current code.
|
||||
panic("mul called with negative w")
|
||||
ww := gf{[x448Limbs]uint32{(uint32)(-w)}}
|
||||
a.mul(b, &ww)
|
||||
a.sub(&zero, a)
|
||||
}
|
||||
}
|
||||
|
||||
// canon canonicalizes.
|
||||
func (a *gf) canon() {
|
||||
a.reduce()
|
||||
|
||||
// Subtract p with borrow.
|
||||
var carry int64
|
||||
for i, v := range a.limb {
|
||||
carry = carry + (int64)(v) - (int64)(p.limb[i])
|
||||
a.limb[i] = (uint32)(carry & lMask)
|
||||
carry >>= lBits
|
||||
}
|
||||
|
||||
addback := carry
|
||||
carry = 0
|
||||
|
||||
// Add it back.
|
||||
for i, v := range a.limb {
|
||||
carry = carry + (int64)(v) + (int64)(p.limb[i]&(uint32)(addback))
|
||||
a.limb[i] = uint32(carry & lMask)
|
||||
carry >>= lBits
|
||||
}
|
||||
}
|
||||
|
||||
// deser deserializes into the limb representation.
|
||||
func (s *gf) deser(ser *[x448Bytes]byte) {
|
||||
var buf uint64
|
||||
bits := uint(0)
|
||||
k := 0
|
||||
|
||||
for i, v := range ser {
|
||||
buf |= (uint64)(v) << bits
|
||||
for bits += 8; (bits >= lBits || i == x448Bytes-1) && k < x448Limbs; bits, buf = bits-lBits, buf>>lBits {
|
||||
s.limb[k] = (uint32)(buf & lMask)
|
||||
k++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ser serializes into byte representation.
|
||||
func (a *gf) ser(ser *[x448Bytes]byte) {
|
||||
a.canon()
|
||||
k := 0
|
||||
bits := uint(0)
|
||||
var buf uint64
|
||||
for i, v := range a.limb {
|
||||
buf |= (uint64)(v) << bits
|
||||
for bits += lBits; (bits >= 8 || i == x448Limbs-1) && k < x448Bytes; bits, buf = bits-8, buf>>8 {
|
||||
ser[k] = (byte)(buf)
|
||||
k++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
if x448Limbs != 16 {
|
||||
panic("x448Limbs != 16, unrolled loops likely broken")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2020, Cisco Systems
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. 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.
|
||||
|
||||
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 HOLDER 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.
|
|
@ -0,0 +1,21 @@
|
|||
# HPKE
|
||||
|
||||
[](https://coveralls.io/github/cisco/go-hpke?branch=ci)
|
||||
|
||||
This repo provides a Go implementation of the HPKE primitive proposed for discussion at CFRG.
|
||||
|
||||
https://tools.ietf.org/html/draft-irtf-cfrg-hpke
|
||||
|
||||
## Test vector generation
|
||||
|
||||
To generate test vectors, run:
|
||||
|
||||
```
|
||||
$ HPKE_TEST_VECTORS_OUT=test-vectors.json go test -v -run TestVectorGenerate
|
||||
```
|
||||
|
||||
To check test vectors, run:
|
||||
|
||||
```
|
||||
$ HPKE_TEST_VECTORS_IN=test-vectors.json go test -v -run TestVectorVerify
|
||||
```
|
|
@ -0,0 +1,990 @@
|
|||
package hpke
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/elliptic"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
mrand "math/rand"
|
||||
|
||||
_ "crypto/sha256"
|
||||
_ "crypto/sha512"
|
||||
|
||||
"git.schwanenlied.me/yawning/x448.git"
|
||||
"github.com/cloudflare/circl/dh/sidh"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
////////
|
||||
// DHKEM
|
||||
|
||||
type dhScheme interface {
|
||||
ID() KEMID
|
||||
DeriveKeyPair(ikm []byte) (KEMPrivateKey, KEMPublicKey, error)
|
||||
Serialize(pk KEMPublicKey) []byte
|
||||
Deserialize(enc []byte) (KEMPublicKey, error)
|
||||
DH(priv KEMPrivateKey, pub KEMPublicKey) ([]byte, error)
|
||||
PublicKeySize() int
|
||||
PrivateKeySize() int
|
||||
|
||||
SerializePrivate(sk KEMPrivateKey) []byte
|
||||
DeserializePrivate(enc []byte) (KEMPrivateKey, error)
|
||||
|
||||
internalKDF() KDFScheme
|
||||
}
|
||||
|
||||
type dhkemScheme struct {
|
||||
group dhScheme
|
||||
skE KEMPrivateKey
|
||||
}
|
||||
|
||||
func (s dhkemScheme) ID() KEMID {
|
||||
return s.group.ID()
|
||||
}
|
||||
|
||||
func (s dhkemScheme) DeriveKeyPair(ikm []byte) (KEMPrivateKey, KEMPublicKey, error) {
|
||||
return s.group.DeriveKeyPair(ikm)
|
||||
}
|
||||
|
||||
func (s dhkemScheme) Serialize(pk KEMPublicKey) []byte {
|
||||
return s.group.Serialize(pk)
|
||||
}
|
||||
|
||||
func (s dhkemScheme) SerializePrivate(sk KEMPrivateKey) []byte {
|
||||
return s.group.SerializePrivate(sk)
|
||||
}
|
||||
|
||||
func (s dhkemScheme) Deserialize(enc []byte) (KEMPublicKey, error) {
|
||||
return s.group.Deserialize(enc)
|
||||
}
|
||||
|
||||
func (s dhkemScheme) DeserializePrivate(enc []byte) (KEMPrivateKey, error) {
|
||||
return s.group.DeserializePrivate(enc)
|
||||
}
|
||||
|
||||
func (s *dhkemScheme) setEphemeralKeyPair(skE KEMPrivateKey) {
|
||||
s.skE = skE
|
||||
}
|
||||
|
||||
func (s dhkemScheme) getEphemeralKeyPair(rand io.Reader) (KEMPrivateKey, KEMPublicKey, error) {
|
||||
if s.skE != nil {
|
||||
return s.skE, s.skE.PublicKey(), nil
|
||||
}
|
||||
|
||||
ikm := make([]byte, s.PrivateKeySize())
|
||||
rand.Read(ikm)
|
||||
|
||||
return s.group.DeriveKeyPair(ikm)
|
||||
}
|
||||
|
||||
func (s dhkemScheme) extractAndExpand(dh []byte, kemContext []byte, Nsecret int) []byte {
|
||||
suiteID := kemSuiteFromID(s.ID())
|
||||
eae_prk := s.group.internalKDF().LabeledExtract(nil, suiteID, "eae_prk", dh)
|
||||
return s.group.internalKDF().LabeledExpand(eae_prk, suiteID, "shared_secret", kemContext, Nsecret)
|
||||
}
|
||||
|
||||
func (s dhkemScheme) Encap(rand io.Reader, pkR KEMPublicKey) ([]byte, []byte, error) {
|
||||
skE, pkE, err := s.getEphemeralKeyPair(rand)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
dh, err := s.group.DH(skE, pkR)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
enc := s.group.Serialize(pkE)
|
||||
pkRm := s.group.Serialize(pkR)
|
||||
|
||||
kemContext := make([]byte, len(enc)+len(pkRm))
|
||||
copy(kemContext, enc)
|
||||
copy(kemContext[len(enc):], pkRm)
|
||||
|
||||
Nsecret := s.group.internalKDF().OutputSize()
|
||||
sharedSecret := s.extractAndExpand(dh, kemContext, Nsecret)
|
||||
|
||||
return sharedSecret, enc, nil
|
||||
}
|
||||
|
||||
func (s dhkemScheme) Decap(enc []byte, skR KEMPrivateKey) ([]byte, error) {
|
||||
pkE, err := s.group.Deserialize(enc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dh, err := s.group.DH(skR, pkE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkRm := s.group.Serialize(skR.PublicKey())
|
||||
|
||||
kemContext := make([]byte, len(enc)+len(pkRm))
|
||||
copy(kemContext, enc)
|
||||
copy(kemContext[len(enc):], pkRm)
|
||||
|
||||
Nsecret := s.group.internalKDF().OutputSize()
|
||||
sharedSecret := s.extractAndExpand(dh, kemContext, Nsecret)
|
||||
|
||||
return sharedSecret, nil
|
||||
}
|
||||
|
||||
func (s dhkemScheme) AuthEncap(rand io.Reader, pkR KEMPublicKey, skS KEMPrivateKey) ([]byte, []byte, error) {
|
||||
skE, pkE, err := s.getEphemeralKeyPair(rand)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
dhER, err := s.group.DH(skE, pkR)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
dhIR, err := s.group.DH(skS, pkR)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
dh := append(dhER, dhIR...)
|
||||
|
||||
enc := s.group.Serialize(pkE)
|
||||
pkRm := s.group.Serialize(pkR)
|
||||
pkSm := s.group.Serialize(skS.PublicKey())
|
||||
|
||||
Nenc := len(enc)
|
||||
Npk := len(pkRm)
|
||||
Nsk := len(pkSm)
|
||||
kemContext := make([]byte, Nenc+Npk+Nsk)
|
||||
copy(kemContext[:Nenc], enc)
|
||||
copy(kemContext[Nenc:Nenc+Npk], pkRm)
|
||||
copy(kemContext[Nenc+Npk:], pkSm)
|
||||
|
||||
Nsecret := s.group.internalKDF().OutputSize()
|
||||
sharedSecret := s.extractAndExpand(dh, kemContext, Nsecret)
|
||||
|
||||
return sharedSecret, enc, nil
|
||||
}
|
||||
|
||||
func (s dhkemScheme) AuthDecap(enc []byte, skR KEMPrivateKey, pkS KEMPublicKey) ([]byte, error) {
|
||||
pkE, err := s.group.Deserialize(enc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dhER, err := s.group.DH(skR, pkE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dhIR, err := s.group.DH(skR, pkS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dh := append(dhER, dhIR...)
|
||||
|
||||
pkRm := s.group.Serialize(skR.PublicKey())
|
||||
pkSm := s.group.Serialize(pkS)
|
||||
|
||||
Nenc := len(enc)
|
||||
Npk := len(pkRm)
|
||||
Nsk := len(pkSm)
|
||||
kemContext := make([]byte, Nenc+Npk+Nsk)
|
||||
copy(kemContext[:Nenc], enc)
|
||||
copy(kemContext[Nenc:Nenc+Npk], pkRm)
|
||||
copy(kemContext[Nenc+Npk:], pkSm)
|
||||
|
||||
Nsecret := s.group.internalKDF().OutputSize()
|
||||
sharedSecret := s.extractAndExpand(dh, kemContext, Nsecret)
|
||||
|
||||
return sharedSecret, nil
|
||||
}
|
||||
|
||||
func (s dhkemScheme) PublicKeySize() int {
|
||||
return s.group.PublicKeySize()
|
||||
}
|
||||
|
||||
func (s dhkemScheme) PrivateKeySize() int {
|
||||
return s.group.PrivateKeySize()
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
// ECDH with NIST curves
|
||||
|
||||
type ecdhPrivateKey struct {
|
||||
curve elliptic.Curve
|
||||
d []byte
|
||||
x, y *big.Int
|
||||
}
|
||||
|
||||
func (priv ecdhPrivateKey) PublicKey() KEMPublicKey {
|
||||
return &ecdhPublicKey{priv.curve, priv.x, priv.y}
|
||||
}
|
||||
|
||||
type ecdhPublicKey struct {
|
||||
curve elliptic.Curve
|
||||
x, y *big.Int
|
||||
}
|
||||
|
||||
type ecdhScheme struct {
|
||||
curve elliptic.Curve
|
||||
KDF KDFScheme
|
||||
skE KEMPrivateKey
|
||||
}
|
||||
|
||||
func (s ecdhScheme) internalKDF() KDFScheme {
|
||||
return s.KDF
|
||||
}
|
||||
|
||||
func (s ecdhScheme) ID() KEMID {
|
||||
switch s.curve.Params().Name {
|
||||
case "P-256":
|
||||
return DHKEM_P256
|
||||
case "P-521":
|
||||
return DHKEM_P521
|
||||
}
|
||||
panic(fmt.Sprintf("Unsupported curve: %s", s.curve.Params().Name))
|
||||
}
|
||||
|
||||
func (s ecdhScheme) privateKeyBitmask() uint8 {
|
||||
switch s.curve.Params().Name {
|
||||
case "P-256":
|
||||
return 0xFF
|
||||
case "P-521":
|
||||
return 0x01
|
||||
}
|
||||
panic(fmt.Sprintf("Unsupported curve: %s", s.curve.Params().Name))
|
||||
}
|
||||
|
||||
func (s ecdhScheme) DeriveKeyPair(ikm []byte) (KEMPrivateKey, KEMPublicKey, error) {
|
||||
suiteID := kemSuiteFromID(s.ID())
|
||||
dkp_prk := s.KDF.LabeledExtract(nil, suiteID, "dkp_prk", ikm)
|
||||
counter := 0
|
||||
for {
|
||||
if counter > 255 {
|
||||
return nil, nil, fmt.Errorf("Error deriving key pair")
|
||||
}
|
||||
|
||||
bytes := s.KDF.LabeledExpand(dkp_prk, suiteID, "candidate", []byte{uint8(counter)}, s.PrivateKeySize())
|
||||
bytes[0] = bytes[0] & s.privateKeyBitmask()
|
||||
|
||||
sk, err := s.DeserializePrivate(bytes)
|
||||
if err == nil {
|
||||
return sk, sk.PublicKey(), nil
|
||||
}
|
||||
|
||||
counter = counter + 1
|
||||
}
|
||||
|
||||
return nil, nil, fmt.Errorf("Error deriving key pair")
|
||||
}
|
||||
|
||||
func (s ecdhScheme) Serialize(pk KEMPublicKey) []byte {
|
||||
if pk == nil {
|
||||
return nil
|
||||
}
|
||||
raw := pk.(*ecdhPublicKey)
|
||||
return elliptic.Marshal(raw.curve, raw.x, raw.y)
|
||||
}
|
||||
|
||||
func (s ecdhScheme) SerializePrivate(sk KEMPrivateKey) []byte {
|
||||
if sk == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
raw := sk.(*ecdhPrivateKey)
|
||||
copied := make([]byte, len(raw.d))
|
||||
copy(copied, raw.d)
|
||||
return copied
|
||||
}
|
||||
|
||||
func (s ecdhScheme) Deserialize(enc []byte) (KEMPublicKey, error) {
|
||||
x, y := elliptic.Unmarshal(s.curve, enc)
|
||||
if x == nil {
|
||||
return nil, fmt.Errorf("Error deserializing public key")
|
||||
}
|
||||
|
||||
return &ecdhPublicKey{s.curve, x, y}, nil
|
||||
}
|
||||
|
||||
func (s ecdhScheme) DeserializePrivate(enc []byte) (KEMPrivateKey, error) {
|
||||
if enc == nil {
|
||||
return nil, fmt.Errorf("Invalid input")
|
||||
}
|
||||
|
||||
x, y := s.curve.Params().ScalarBaseMult(enc)
|
||||
return &ecdhPrivateKey{s.curve, enc, x, y}, nil
|
||||
}
|
||||
|
||||
func (s ecdhScheme) DH(priv KEMPrivateKey, pub KEMPublicKey) ([]byte, error) {
|
||||
ecdhPriv, ok := priv.(*ecdhPrivateKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Private key not suitable for ECDH")
|
||||
}
|
||||
|
||||
ecdhPub, ok := pub.(*ecdhPublicKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Public key not suitable for ECDH")
|
||||
}
|
||||
|
||||
x, _ := s.curve.Params().ScalarMult(ecdhPub.x, ecdhPub.y, ecdhPriv.d)
|
||||
xx := x.Bytes()
|
||||
|
||||
size := (s.curve.Params().BitSize + 7) >> 3
|
||||
pad := make([]byte, size-len(xx))
|
||||
dh := append(pad, xx...)
|
||||
|
||||
return dh, nil
|
||||
}
|
||||
|
||||
func (s ecdhScheme) PublicKeySize() int {
|
||||
feSize := (s.curve.Params().BitSize + 7) >> 3
|
||||
return 1 + 2*feSize
|
||||
}
|
||||
|
||||
func (s ecdhScheme) PrivateKeySize() int {
|
||||
return (s.curve.Params().BitSize + 7) >> 3
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// ECDH with X25519
|
||||
|
||||
type x25519PrivateKey struct {
|
||||
val [32]byte
|
||||
}
|
||||
|
||||
func (priv x25519PrivateKey) PublicKey() KEMPublicKey {
|
||||
pub := &x25519PublicKey{}
|
||||
curve25519.ScalarBaseMult(&pub.val, &priv.val)
|
||||
return pub
|
||||
}
|
||||
|
||||
type x25519PublicKey struct {
|
||||
val [32]byte
|
||||
}
|
||||
|
||||
type x25519Scheme struct {
|
||||
skE KEMPrivateKey
|
||||
}
|
||||
|
||||
func (s x25519Scheme) internalKDF() KDFScheme {
|
||||
return hkdfScheme{hash: crypto.SHA256}
|
||||
}
|
||||
|
||||
func (s x25519Scheme) ID() KEMID {
|
||||
return DHKEM_X25519
|
||||
}
|
||||
|
||||
func (s x25519Scheme) DeriveKeyPair(ikm []byte) (KEMPrivateKey, KEMPublicKey, error) {
|
||||
suiteID := kemSuiteFromID(s.ID())
|
||||
dkp_prk := s.internalKDF().LabeledExtract(nil, suiteID, "dkp_prk", ikm)
|
||||
sk_bytes := s.internalKDF().LabeledExpand(dkp_prk, suiteID, "sk", nil, s.PrivateKeySize())
|
||||
sk, err := s.DeserializePrivate(sk_bytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
} else {
|
||||
return sk, sk.PublicKey(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s x25519Scheme) Serialize(pk KEMPublicKey) []byte {
|
||||
if pk == nil {
|
||||
return nil
|
||||
}
|
||||
raw := pk.(*x25519PublicKey)
|
||||
return raw.val[:]
|
||||
}
|
||||
|
||||
func (s x25519Scheme) SerializePrivate(sk KEMPrivateKey) []byte {
|
||||
if sk == nil {
|
||||
return nil
|
||||
}
|
||||
raw := sk.(*x25519PrivateKey)
|
||||
return raw.val[:]
|
||||
}
|
||||
|
||||
func (s x25519Scheme) Deserialize(enc []byte) (KEMPublicKey, error) {
|
||||
if len(enc) != 32 {
|
||||
return nil, fmt.Errorf("Error deserializing X25519 public key")
|
||||
}
|
||||
|
||||
pub := &x25519PublicKey{}
|
||||
copy(pub.val[:], enc)
|
||||
return pub, nil
|
||||
}
|
||||
|
||||
func (s x25519Scheme) DeserializePrivate(enc []byte) (KEMPrivateKey, error) {
|
||||
if enc == nil {
|
||||
return nil, fmt.Errorf("Invalid input")
|
||||
}
|
||||
|
||||
if len(enc) != 32 {
|
||||
return nil, fmt.Errorf("Error deserializing X25519 private key")
|
||||
}
|
||||
|
||||
key := &x25519PrivateKey{}
|
||||
copy(key.val[:], enc[0:32])
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (s x25519Scheme) DH(priv KEMPrivateKey, pub KEMPublicKey) ([]byte, error) {
|
||||
xPriv, ok := priv.(*x25519PrivateKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Private key not suitable for X25519: %+v", priv)
|
||||
}
|
||||
|
||||
xPub, ok := pub.(*x25519PublicKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Private key not suitable for X25519")
|
||||
}
|
||||
|
||||
sharedSecret, err := curve25519.X25519(xPriv.val[:], xPub.val[:])
|
||||
return sharedSecret, err
|
||||
}
|
||||
|
||||
func (s x25519Scheme) PublicKeySize() int {
|
||||
return 32
|
||||
}
|
||||
|
||||
func (s x25519Scheme) PrivateKeySize() int {
|
||||
return 32
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// ECDH with X448
|
||||
|
||||
type x448PrivateKey struct {
|
||||
val [56]byte
|
||||
}
|
||||
|
||||
func (priv x448PrivateKey) PublicKey() KEMPublicKey {
|
||||
pub := &x448PublicKey{}
|
||||
x448.ScalarBaseMult(&pub.val, &priv.val)
|
||||
return pub
|
||||
}
|
||||
|
||||
type x448PublicKey struct {
|
||||
val [56]byte
|
||||
}
|
||||
|
||||
type x448Scheme struct {
|
||||
skE KEMPrivateKey
|
||||
}
|
||||
|
||||
func (s x448Scheme) internalKDF() KDFScheme {
|
||||
return hkdfScheme{hash: crypto.SHA512}
|
||||
}
|
||||
|
||||
func (s x448Scheme) ID() KEMID {
|
||||
return DHKEM_X448
|
||||
}
|
||||
|
||||
func (s x448Scheme) DeriveKeyPair(ikm []byte) (KEMPrivateKey, KEMPublicKey, error) {
|
||||
suiteID := kemSuiteFromID(s.ID())
|
||||
dkp_prk := s.internalKDF().LabeledExtract(nil, suiteID, "dkp_prk", ikm)
|
||||
sk_bytes := s.internalKDF().LabeledExpand(dkp_prk, suiteID, "sk", nil, s.PrivateKeySize())
|
||||
sk, err := s.DeserializePrivate(sk_bytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
} else {
|
||||
return sk, sk.PublicKey(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s x448Scheme) Serialize(pk KEMPublicKey) []byte {
|
||||
if pk == nil {
|
||||
return nil
|
||||
}
|
||||
raw := pk.(*x448PublicKey)
|
||||
return raw.val[:]
|
||||
}
|
||||
|
||||
func (s x448Scheme) SerializePrivate(sk KEMPrivateKey) []byte {
|
||||
if sk == nil {
|
||||
return nil
|
||||
}
|
||||
raw := sk.(*x448PrivateKey)
|
||||
return raw.val[:]
|
||||
}
|
||||
|
||||
func (s x448Scheme) Deserialize(enc []byte) (KEMPublicKey, error) {
|
||||
if len(enc) != 56 {
|
||||
return nil, fmt.Errorf("Error deserializing X448 public key")
|
||||
}
|
||||
|
||||
pub := &x448PublicKey{}
|
||||
copy(pub.val[:], enc)
|
||||
return pub, nil
|
||||
}
|
||||
|
||||
func (s x448Scheme) DeserializePrivate(enc []byte) (KEMPrivateKey, error) {
|
||||
if enc == nil {
|
||||
return nil, fmt.Errorf("Invalid input")
|
||||
}
|
||||
|
||||
if len(enc) != 56 {
|
||||
return nil, fmt.Errorf("Error deserializing X448 private key")
|
||||
}
|
||||
|
||||
key := &x448PrivateKey{}
|
||||
copy(key.val[:], enc[0:56])
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (s x448Scheme) DH(priv KEMPrivateKey, pub KEMPublicKey) ([]byte, error) {
|
||||
xPriv, ok := priv.(*x448PrivateKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Private key not suitable for X448: %+v", priv)
|
||||
}
|
||||
|
||||
xPub, ok := pub.(*x448PublicKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Public key not suitable for X448: %+v", pub)
|
||||
}
|
||||
|
||||
var sharedSecret, zero [56]byte
|
||||
x448.ScalarMult(&sharedSecret, &xPriv.val, &xPub.val)
|
||||
if subtle.ConstantTimeCompare(sharedSecret[:], zero[:]) == 1 {
|
||||
return nil, fmt.Errorf("bad input point: low order point")
|
||||
}
|
||||
|
||||
return sharedSecret[:], nil
|
||||
}
|
||||
|
||||
func (s x448Scheme) PublicKeySize() int {
|
||||
return 56
|
||||
}
|
||||
|
||||
func (s x448Scheme) PrivateKeySize() int {
|
||||
return 56
|
||||
}
|
||||
|
||||
///////
|
||||
// SIKE
|
||||
|
||||
type sikePublicKey struct {
|
||||
field uint8
|
||||
pub *sidh.PublicKey
|
||||
}
|
||||
|
||||
type sikePrivateKey struct {
|
||||
field uint8
|
||||
priv *sidh.PrivateKey
|
||||
pub *sidh.PublicKey
|
||||
}
|
||||
|
||||
func (priv sikePrivateKey) PublicKey() KEMPublicKey {
|
||||
return &sikePublicKey{priv.field, priv.pub}
|
||||
}
|
||||
|
||||
type sikeScheme struct {
|
||||
field uint8
|
||||
KDF KDFScheme
|
||||
}
|
||||
|
||||
func (s sikeScheme) internalKDF() KDFScheme {
|
||||
return s.KDF
|
||||
}
|
||||
|
||||
func (s sikeScheme) ID() KEMID {
|
||||
switch s.field {
|
||||
case sidh.Fp503:
|
||||
return KEM_SIKE503
|
||||
case sidh.Fp751:
|
||||
return KEM_SIKE751
|
||||
}
|
||||
panic(fmt.Sprintf("Unsupported field: %d", s.field))
|
||||
}
|
||||
|
||||
func (s sikeScheme) generateKeyPair(rand io.Reader) (KEMPrivateKey, KEMPublicKey, error) {
|
||||
rawPriv := sidh.NewPrivateKey(s.field, sidh.KeyVariantSike)
|
||||
err := rawPriv.Generate(rand)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
rawPub := sidh.NewPublicKey(s.field, sidh.KeyVariantSike)
|
||||
rawPriv.GeneratePublicKey(rawPub)
|
||||
|
||||
priv := &sikePrivateKey{s.field, rawPriv, rawPub}
|
||||
return priv, priv.PublicKey(), nil
|
||||
}
|
||||
|
||||
func (s sikeScheme) DeriveKeyPair(ikm []byte) (KEMPrivateKey, KEMPublicKey, error) {
|
||||
// Note: DeriveKeyPair is not specified for SIKE, so we just use IKM to
|
||||
// seed a DRBG, and then re-use the other APIs for generating key pairs
|
||||
// from randomness.
|
||||
var seed int64
|
||||
ikmReader := bytes.NewReader(ikm)
|
||||
if err := binary.Read(ikmReader, binary.BigEndian, &seed); err != nil {
|
||||
return nil, nil, fmt.Errorf("Error deriving key pair")
|
||||
}
|
||||
|
||||
source := mrand.NewSource(seed)
|
||||
return s.generateKeyPair(mrand.New(source))
|
||||
}
|
||||
|
||||
func (s sikeScheme) Serialize(pk KEMPublicKey) []byte {
|
||||
if pk == nil {
|
||||
return nil
|
||||
}
|
||||
raw := pk.(*sikePublicKey)
|
||||
out := make([]byte, raw.pub.Size())
|
||||
raw.pub.Export(out)
|
||||
return out
|
||||
}
|
||||
|
||||
func (s sikeScheme) SerializePrivate(sk KEMPrivateKey) []byte {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s sikeScheme) Deserialize(enc []byte) (KEMPublicKey, error) {
|
||||
rawPub := sidh.NewPublicKey(s.field, sidh.KeyVariantSike)
|
||||
if len(enc) != rawPub.Size() {
|
||||
return nil, fmt.Errorf("Invalid public key size: got %d, expected %d", len(enc), rawPub.Size())
|
||||
}
|
||||
|
||||
err := rawPub.Import(enc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &sikePublicKey{s.field, rawPub}, nil
|
||||
}
|
||||
|
||||
func (s sikeScheme) DeserializePrivate(enc []byte) (KEMPrivateKey, error) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s sikeScheme) newKEM(rand io.Reader) (*sidh.KEM, error) {
|
||||
switch s.field {
|
||||
case sidh.Fp503:
|
||||
return sidh.NewSike503(rand), nil
|
||||
case sidh.Fp751:
|
||||
return sidh.NewSike751(rand), nil
|
||||
}
|
||||
return nil, fmt.Errorf("Invalid field")
|
||||
}
|
||||
|
||||
func (s sikeScheme) Encap(rand io.Reader, pkR KEMPublicKey) ([]byte, []byte, error) {
|
||||
raw := pkR.(*sikePublicKey)
|
||||
|
||||
kem, err := s.newKEM(rand)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
enc := make([]byte, kem.CiphertextSize())
|
||||
sharedSecret := make([]byte, s.KDF.OutputSize())
|
||||
err = kem.Encapsulate(enc, sharedSecret, raw.pub)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return sharedSecret, enc, nil
|
||||
}
|
||||
|
||||
type panicReader struct{}
|
||||
|
||||
func (p panicReader) Read(unused []byte) (int, error) {
|
||||
panic("Should not read")
|
||||
}
|
||||
|
||||
func (s sikeScheme) Decap(enc []byte, skR KEMPrivateKey) ([]byte, error) {
|
||||
raw := skR.(*sikePrivateKey)
|
||||
|
||||
kem, err := s.newKEM(panicReader{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sharedSecret := make([]byte, s.KDF.OutputSize())
|
||||
err = kem.Decapsulate(sharedSecret, raw.priv, raw.pub, enc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sharedSecret, nil
|
||||
}
|
||||
|
||||
func (s sikeScheme) PublicKeySize() int {
|
||||
rawPub := sidh.NewPublicKey(s.field, sidh.KeyVariantSike)
|
||||
return rawPub.Size()
|
||||
}
|
||||
|
||||
func (s sikeScheme) PrivateKeySize() int {
|
||||
rawPriv := sidh.NewPrivateKey(s.field, sidh.KeyVariantSike)
|
||||
err := rawPriv.Generate(rand.Reader)
|
||||
if err != nil {
|
||||
panic("PrivateKeySize failed")
|
||||
}
|
||||
|
||||
return rawPriv.Size()
|
||||
}
|
||||
|
||||
func (s sikeScheme) setEphemeralKeyPair(skE KEMPrivateKey) {
|
||||
panic("SIKE cannot use a pre-set ephemeral key pair")
|
||||
}
|
||||
|
||||
//////////
|
||||
// AES-GCM
|
||||
|
||||
type aesgcmScheme struct {
|
||||
keySize int
|
||||
}
|
||||
|
||||
func (s aesgcmScheme) ID() AEADID {
|
||||
switch s.keySize {
|
||||
case 16:
|
||||
return AEAD_AESGCM128
|
||||
case 32:
|
||||
return AEAD_AESGCM256
|
||||
}
|
||||
panic(fmt.Sprintf("Unsupported key size: %d", s.keySize))
|
||||
|
||||
}
|
||||
|
||||
func (s aesgcmScheme) New(key []byte) (cipher.AEAD, error) {
|
||||
if len(key) != s.keySize {
|
||||
return nil, fmt.Errorf("Incorrect key size %d != %d", len(key), s.keySize)
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cipher.NewGCM(block)
|
||||
}
|
||||
|
||||
func (s aesgcmScheme) KeySize() int {
|
||||
return s.keySize
|
||||
}
|
||||
|
||||
func (s aesgcmScheme) NonceSize() int {
|
||||
return 12
|
||||
}
|
||||
|
||||
//////////
|
||||
// ChaCha20-Poly1305
|
||||
|
||||
type chachaPolyScheme struct {
|
||||
}
|
||||
|
||||
func (s chachaPolyScheme) ID() AEADID {
|
||||
return AEAD_CHACHA20POLY1305
|
||||
}
|
||||
|
||||
func (s chachaPolyScheme) New(key []byte) (cipher.AEAD, error) {
|
||||
return chacha20poly1305.New(key)
|
||||
}
|
||||
|
||||
func (s chachaPolyScheme) KeySize() int {
|
||||
return chacha20poly1305.KeySize
|
||||
}
|
||||
|
||||
func (s chachaPolyScheme) NonceSize() int {
|
||||
return chacha20poly1305.NonceSize
|
||||
}
|
||||
|
||||
///////
|
||||
// HKDF
|
||||
|
||||
type hkdfScheme struct {
|
||||
hash crypto.Hash
|
||||
}
|
||||
|
||||
func (s hkdfScheme) ID() KDFID {
|
||||
switch s.hash {
|
||||
case crypto.SHA256:
|
||||
return KDF_HKDF_SHA256
|
||||
case crypto.SHA384:
|
||||
return KDF_HKDF_SHA384
|
||||
case crypto.SHA512:
|
||||
return KDF_HKDF_SHA512
|
||||
}
|
||||
panic(fmt.Sprintf("Unsupported hash: %d", s.hash))
|
||||
}
|
||||
|
||||
func (s hkdfScheme) Hash(message []byte) []byte {
|
||||
h := s.hash.New()
|
||||
h.Write(message)
|
||||
return h.Sum(nil)
|
||||
}
|
||||
|
||||
func (s hkdfScheme) Extract(salt, ikm []byte) []byte {
|
||||
saltOrZero := salt
|
||||
|
||||
// if [salt is] not provided, it is set to a string of HashLen zeros
|
||||
if salt == nil {
|
||||
saltOrZero = make([]byte, s.hash.Size())
|
||||
}
|
||||
|
||||
h := hmac.New(s.hash.New, saltOrZero)
|
||||
h.Write(ikm)
|
||||
return h.Sum(nil)
|
||||
}
|
||||
|
||||
func (s hkdfScheme) Expand(prk, info []byte, outLen int) []byte {
|
||||
out := []byte{}
|
||||
T := []byte{}
|
||||
i := byte(1)
|
||||
for len(out) < outLen {
|
||||
block := append(T, info...)
|
||||
block = append(block, i)
|
||||
|
||||
h := hmac.New(s.hash.New, prk)
|
||||
h.Write(block)
|
||||
|
||||
T = h.Sum(nil)
|
||||
out = append(out, T...)
|
||||
i++
|
||||
}
|
||||
return out[:outLen]
|
||||
}
|
||||
|
||||
func (s hkdfScheme) LabeledExtract(salt []byte, suiteID []byte, label string, ikm []byte) []byte {
|
||||
labeledIKM := append([]byte(rfcLabel), suiteID...)
|
||||
labeledIKM = append(labeledIKM, []byte(label)...)
|
||||
labeledIKM = append(labeledIKM, ikm...)
|
||||
return s.Extract(salt, labeledIKM)
|
||||
}
|
||||
|
||||
func (s hkdfScheme) LabeledExpand(prk []byte, suiteID []byte, label string, info []byte, L int) []byte {
|
||||
if L > (1 << 16) {
|
||||
panic("Expand length cannot be larger than 2^16")
|
||||
}
|
||||
|
||||
lengthBuffer := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(lengthBuffer, uint16(L))
|
||||
labeledLength := append(lengthBuffer, []byte(rfcLabel)...)
|
||||
labeledInfo := append(labeledLength, suiteID...)
|
||||
labeledInfo = append(labeledInfo, []byte(label)...)
|
||||
labeledInfo = append(labeledInfo, info...)
|
||||
|
||||
return s.Expand(prk, labeledInfo, L)
|
||||
}
|
||||
|
||||
func (s hkdfScheme) OutputSize() int {
|
||||
return s.hash.Size()
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// Pre-defined KEM identifiers
|
||||
|
||||
type KEMID uint16
|
||||
|
||||
const (
|
||||
DHKEM_P256 KEMID = 0x0010
|
||||
DHKEM_P521 KEMID = 0x0012
|
||||
DHKEM_X25519 KEMID = 0x0020
|
||||
DHKEM_X448 KEMID = 0x0021
|
||||
KEM_SIKE503 KEMID = 0xFFFE
|
||||
KEM_SIKE751 KEMID = 0xFFFF
|
||||
)
|
||||
|
||||
var kems = map[KEMID]KEMScheme{
|
||||
DHKEM_X25519: &dhkemScheme{group: x25519Scheme{}},
|
||||
DHKEM_X448: &dhkemScheme{group: x448Scheme{}},
|
||||
DHKEM_P256: &dhkemScheme{group: ecdhScheme{curve: elliptic.P256(), KDF: hkdfScheme{hash: crypto.SHA256}}},
|
||||
DHKEM_P521: &dhkemScheme{group: ecdhScheme{curve: elliptic.P521(), KDF: hkdfScheme{hash: crypto.SHA512}}},
|
||||
KEM_SIKE503: &sikeScheme{field: sidh.Fp503, KDF: hkdfScheme{hash: crypto.SHA512}},
|
||||
KEM_SIKE751: &sikeScheme{field: sidh.Fp751, KDF: hkdfScheme{hash: crypto.SHA512}},
|
||||
}
|
||||
|
||||
func newKEMScheme(kemID KEMID) (KEMScheme, bool) {
|
||||
switch kemID {
|
||||
case DHKEM_X25519:
|
||||
return &dhkemScheme{group: x25519Scheme{}}, true
|
||||
case DHKEM_X448:
|
||||
return &dhkemScheme{group: x448Scheme{}}, true
|
||||
case DHKEM_P256:
|
||||
return &dhkemScheme{group: ecdhScheme{curve: elliptic.P256(), KDF: hkdfScheme{hash: crypto.SHA256}}}, true
|
||||
case DHKEM_P521:
|
||||
return &dhkemScheme{group: ecdhScheme{curve: elliptic.P521(), KDF: hkdfScheme{hash: crypto.SHA512}}}, true
|
||||
case KEM_SIKE503:
|
||||
return &sikeScheme{field: sidh.Fp503, KDF: hkdfScheme{hash: crypto.SHA512}}, true
|
||||
case KEM_SIKE751:
|
||||
return &sikeScheme{field: sidh.Fp751, KDF: hkdfScheme{hash: crypto.SHA512}}, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// Pre-defined KDF identifiers
|
||||
|
||||
type KDFID uint16
|
||||
|
||||
const (
|
||||
KDF_HKDF_SHA256 KDFID = 0x0001
|
||||
KDF_HKDF_SHA384 KDFID = 0x0002
|
||||
KDF_HKDF_SHA512 KDFID = 0x0003
|
||||
)
|
||||
|
||||
var kdfs = map[KDFID]KDFScheme{
|
||||
KDF_HKDF_SHA256: hkdfScheme{hash: crypto.SHA256},
|
||||
KDF_HKDF_SHA384: hkdfScheme{hash: crypto.SHA384},
|
||||
KDF_HKDF_SHA512: hkdfScheme{hash: crypto.SHA512},
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// Pre-defined AEAD identifiers
|
||||
|
||||
type AEADID uint16
|
||||
|
||||
const (
|
||||
AEAD_AESGCM128 AEADID = 0x0001
|
||||
AEAD_AESGCM256 AEADID = 0x0002
|
||||
AEAD_CHACHA20POLY1305 AEADID = 0x0003
|
||||
)
|
||||
|
||||
var aeads = map[AEADID]AEADScheme{
|
||||
AEAD_AESGCM128: aesgcmScheme{keySize: 16},
|
||||
AEAD_AESGCM256: aesgcmScheme{keySize: 32},
|
||||
AEAD_CHACHA20POLY1305: chachaPolyScheme{},
|
||||
}
|
||||
|
||||
func AssembleCipherSuite(kemID KEMID, kdfID KDFID, aeadID AEADID) (CipherSuite, error) {
|
||||
kem, ok := newKEMScheme(kemID)
|
||||
if !ok {
|
||||
return CipherSuite{}, fmt.Errorf("Unknown KEM id")
|
||||
}
|
||||
|
||||
kdf, ok := kdfs[kdfID]
|
||||
if !ok {
|
||||
return CipherSuite{}, fmt.Errorf("Unknown KDF id")
|
||||
}
|
||||
|
||||
aead, ok := aeads[aeadID]
|
||||
if !ok {
|
||||
return CipherSuite{}, fmt.Errorf("Unknown AEAD id")
|
||||
}
|
||||
|
||||
return CipherSuite{
|
||||
KEM: kem,
|
||||
KDF: kdf,
|
||||
AEAD: aead,
|
||||
}, nil
|
||||
}
|
||||
|
||||
//////////
|
||||
// Helpers
|
||||
|
||||
func kemSuiteFromID(id KEMID) []byte {
|
||||
idBuffer := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(idBuffer, uint16(id))
|
||||
return append([]byte("KEM"), idBuffer...)
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
import sys
|
||||
import json
|
||||
import textwrap
|
||||
|
||||
ordered_keys = [
|
||||
# Mode and ciphersuite parameters
|
||||
"mode", "kem_id", "kdf_id", "aead_id", "info",
|
||||
# Private key material
|
||||
"ikmE", "pkEm", "skEm",
|
||||
"ikmR", "pkRm", "skRm",
|
||||
"ikmS", "pkSm", "skSm",
|
||||
"psk", "psk_id",
|
||||
# Derived context
|
||||
"enc", "shared_secret", "key_schedule_context", "secret", "key", "base_nonce", "exporter_secret",
|
||||
]
|
||||
|
||||
ordered_encryption_keys = [
|
||||
"plaintext", "aad", "nonce", "ciphertext",
|
||||
]
|
||||
|
||||
encryption_count_keys = [
|
||||
0, 1, 2, 4, 10, 32, 255, 256, 257
|
||||
]
|
||||
|
||||
def entry_kem(entry):
|
||||
return kemMap[entry["kem_id"]]
|
||||
|
||||
def entry_kem_value(entry):
|
||||
return entry["kem_id"]
|
||||
|
||||
def entry_kdf(entry):
|
||||
return kdfMap[entry["kdf_id"]]
|
||||
|
||||
def entry_kdf_value(entry):
|
||||
return entry["kdf_id"]
|
||||
|
||||
def entry_aead(entry):
|
||||
return aeadMap[entry["aead_id"]]
|
||||
|
||||
def entry_aead_value(entry):
|
||||
return entry["aead_id"]
|
||||
|
||||
def entry_mode(entry):
|
||||
return modeMap[entry["mode"]]
|
||||
|
||||
def entry_mode_value(entry):
|
||||
return entry["mode"]
|
||||
|
||||
modeBase = 0x00
|
||||
modePSK = 0x01
|
||||
modeAuth = 0x02
|
||||
modeAuthPSK = 0x03
|
||||
modeMap = {modeBase: "Base", modePSK: "PSK", modeAuth: "Auth", modeAuthPSK: "AuthPSK"}
|
||||
|
||||
kem_idP256 = 0x0010
|
||||
kem_idP521 = 0x0012
|
||||
kem_idX25519 = 0x0020
|
||||
kemMap = {kem_idX25519: "DHKEM(X25519, HKDF-SHA256)", kem_idP256: "DHKEM(P-256, HKDF-SHA256)", kem_idP521: "DHKEM(P-521, HKDF-SHA512)"}
|
||||
|
||||
kdf_idSHA256 = 0x0001
|
||||
kdf_idSHA512 = 0x0003
|
||||
kdfMap = {kdf_idSHA256: "HKDF-SHA256", kdf_idSHA512: "HKDF-SHA512"}
|
||||
|
||||
aead_idAES128GCM = 0x0001
|
||||
aead_idAES256GCM = 0x0002
|
||||
aead_idChaCha20Poly1305 = 0x0003
|
||||
aeadMap = {aead_idAES128GCM: "AES-128-GCM", aead_idAES256GCM: "AES-256-GCM", aead_idChaCha20Poly1305: "ChaCha20Poly1305"}
|
||||
|
||||
class CipherSuite(object):
|
||||
def __init__(self, kem_id, kdf_id, aead_id):
|
||||
self.kem_id = kem_id
|
||||
self.kdf_id = kdf_id
|
||||
self.aead_id = aead_id
|
||||
|
||||
def __str__(self):
|
||||
return kemMap[self.kem_id] + ", " + kdfMap[self.kdf_id] + ", " + aeadMap[self.aead_id]
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
def matches_vector(self, vector):
|
||||
return self.kem_id == entry_kem_value(vector) and self.kdf_id == entry_kdf_value(vector) and self.aead_id == entry_aead_value(vector)
|
||||
|
||||
testSuites = [
|
||||
CipherSuite(kem_idX25519, kdf_idSHA256, aead_idAES128GCM),
|
||||
CipherSuite(kem_idX25519, kdf_idSHA256, aead_idChaCha20Poly1305),
|
||||
CipherSuite(kem_idP256, kdf_idSHA256, aead_idAES128GCM),
|
||||
CipherSuite(kem_idP256, kdf_idSHA512, aead_idAES128GCM),
|
||||
CipherSuite(kem_idP256, kdf_idSHA256, aead_idChaCha20Poly1305),
|
||||
CipherSuite(kem_idP521, kdf_idSHA512, aead_idAES256GCM),
|
||||
]
|
||||
|
||||
def wrap_line(value):
|
||||
return textwrap.fill(value, width=72)
|
||||
|
||||
def format_encryption(entry, count):
|
||||
formatted = wrap_line("sequence number: %d" % count) + "\n"
|
||||
for key in ordered_encryption_keys:
|
||||
if key in entry:
|
||||
formatted = formatted + wrap_line(key + ": " + str(entry[key])) + "\n"
|
||||
return formatted
|
||||
|
||||
def format_encryptions(entry, mode):
|
||||
formatted = "~~~\n"
|
||||
for seq_number in encryption_count_keys:
|
||||
for i, encryption in enumerate(entry["encryptions"]):
|
||||
if i == seq_number:
|
||||
formatted = formatted + format_encryption(encryption, i)
|
||||
if i < len(entry["encryptions"]) - 1:
|
||||
formatted = formatted + "\n"
|
||||
return formatted + "~~~"
|
||||
|
||||
def format_vector(entry, mode):
|
||||
formatted = "~~~\n"
|
||||
for key in ordered_keys:
|
||||
if key in entry:
|
||||
formatted = formatted + wrap_line(key + ": " + str(entry[key])) + "\n"
|
||||
return formatted + "~~~\n"
|
||||
|
||||
with open(sys.argv[1], "r") as fh:
|
||||
data = json.load(fh)
|
||||
for suite in testSuites:
|
||||
print("## " + str(suite))
|
||||
print("")
|
||||
for mode in [modeBase, modePSK, modeAuth, modeAuthPSK]:
|
||||
for vector in data:
|
||||
if suite.matches_vector(vector):
|
||||
if mode == entry_mode_value(vector):
|
||||
print("### " + modeMap[mode] + " Setup Information")
|
||||
print(format_vector(vector, mode))
|
||||
print("#### Encryptions")
|
||||
print(format_encryptions(vector, mode))
|
||||
print("")
|
|
@ -0,0 +1,10 @@
|
|||
module github.com/cisco/go-hpke
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
git.schwanenlied.me/yawning/x448.git v0.0.0-20170617130356-01b048fb03d6
|
||||
github.com/cisco/go-tls-syntax v0.0.0-20200617162716-46b0cfb76b9b
|
||||
github.com/cloudflare/circl v1.0.0
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
||||
)
|
|
@ -0,0 +1,26 @@
|
|||
git.schwanenlied.me/yawning/x448.git v0.0.0-20170617130356-01b048fb03d6 h1:w8IZgCntCe0RuBJp+dENSMwEBl/k8saTgJ5hPca5IWw=
|
||||
git.schwanenlied.me/yawning/x448.git v0.0.0-20170617130356-01b048fb03d6/go.mod h1:wQaGCqEu44ykB17jZHCevrgSVl3KJnwQBObUtrKU4uU=
|
||||
github.com/cisco/go-tls-syntax v0.0.0-20200617162716-46b0cfb76b9b h1:Ves2turKTX7zruivAcUOQg155xggcbv3suVdbKCBQNM=
|
||||
github.com/cisco/go-tls-syntax v0.0.0-20200617162716-46b0cfb76b9b/go.mod h1:0AZAV7lYvynZQ5ErHlGMKH+4QYMyNCFd+AiL9MlrCYA=
|
||||
github.com/cloudflare/circl v1.0.0 h1:64b6pyfCFbYm623ncIkYGNZaOcmIbyd+CjyMi2L9vdI=
|
||||
github.com/cloudflare/circl v1.0.0/go.mod h1:MhjB3NEEhJbTOdLLq964NIUisXDxaE1WkQPUxtgZXiY=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed h1:uPxWBzB3+mlnjy9W58qY1j/cjyFjutgw/Vhan2zLy/A=
|
||||
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -0,0 +1,549 @@
|
|||
package hpke
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/cisco/go-tls-syntax"
|
||||
)
|
||||
|
||||
const (
|
||||
debug = true
|
||||
rfcLabel = "HPKE-06"
|
||||
)
|
||||
|
||||
type KEMPrivateKey interface {
|
||||
PublicKey() KEMPublicKey
|
||||
}
|
||||
|
||||
type KEMPublicKey interface{}
|
||||
|
||||
type KEMScheme interface {
|
||||
ID() KEMID
|
||||
DeriveKeyPair(ikm []byte) (KEMPrivateKey, KEMPublicKey, error)
|
||||
Serialize(pk KEMPublicKey) []byte
|
||||
Deserialize(enc []byte) (KEMPublicKey, error)
|
||||
Encap(rand io.Reader, pkR KEMPublicKey) ([]byte, []byte, error)
|
||||
Decap(enc []byte, skR KEMPrivateKey) ([]byte, error)
|
||||
PublicKeySize() int
|
||||
PrivateKeySize() int
|
||||
|
||||
SerializePrivate(sk KEMPrivateKey) []byte
|
||||
DeserializePrivate(enc []byte) (KEMPrivateKey, error)
|
||||
|
||||
setEphemeralKeyPair(sk KEMPrivateKey)
|
||||
}
|
||||
|
||||
type AuthKEMScheme interface {
|
||||
KEMScheme
|
||||
AuthEncap(rand io.Reader, pkR KEMPublicKey, skS KEMPrivateKey) ([]byte, []byte, error)
|
||||
AuthDecap(enc []byte, skR KEMPrivateKey, pkS KEMPublicKey) ([]byte, error)
|
||||
}
|
||||
|
||||
type KDFScheme interface {
|
||||
ID() KDFID
|
||||
Hash(message []byte) []byte
|
||||
Extract(salt, ikm []byte) []byte
|
||||
Expand(prk, info []byte, L int) []byte
|
||||
LabeledExtract(salt []byte, suiteID []byte, label string, ikm []byte) []byte
|
||||
LabeledExpand(prk []byte, suiteID []byte, label string, info []byte, L int) []byte
|
||||
OutputSize() int
|
||||
}
|
||||
|
||||
type AEADScheme interface {
|
||||
ID() AEADID
|
||||
New(key []byte) (cipher.AEAD, error)
|
||||
KeySize() int
|
||||
NonceSize() int
|
||||
}
|
||||
|
||||
type CipherSuite struct {
|
||||
KEM KEMScheme
|
||||
KDF KDFScheme
|
||||
AEAD AEADScheme
|
||||
}
|
||||
|
||||
func (suite CipherSuite) ID() []byte {
|
||||
suiteID := make([]byte, 6)
|
||||
binary.BigEndian.PutUint16(suiteID, uint16(suite.KEM.ID()))
|
||||
binary.BigEndian.PutUint16(suiteID[2:], uint16(suite.KDF.ID()))
|
||||
binary.BigEndian.PutUint16(suiteID[4:], uint16(suite.AEAD.ID()))
|
||||
return append([]byte("HPKE"), suiteID...)
|
||||
}
|
||||
|
||||
type Mode uint8
|
||||
|
||||
const (
|
||||
modeBase Mode = 0x00
|
||||
modePSK Mode = 0x01
|
||||
modeAuth Mode = 0x02
|
||||
modeAuthPSK Mode = 0x03
|
||||
)
|
||||
|
||||
func logString(val string) {
|
||||
if debug {
|
||||
log.Printf("%s", val)
|
||||
}
|
||||
}
|
||||
|
||||
func logVal(name string, value []byte) {
|
||||
if debug {
|
||||
log.Printf(" %6s %x", name, value)
|
||||
}
|
||||
}
|
||||
|
||||
///////
|
||||
// Core
|
||||
|
||||
func defaultPSK(suite CipherSuite) []byte {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
func defaultPSKID(suite CipherSuite) []byte {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
func verifyPSKInputs(suite CipherSuite, mode Mode, psk, pskID []byte) error {
|
||||
defaultPSK := defaultPSK(suite)
|
||||
defaultPSKID := defaultPSKID(suite)
|
||||
pskMode := map[Mode]bool{modePSK: true, modeAuthPSK: true}
|
||||
|
||||
gotPSK := !bytes.Equal(psk, defaultPSK)
|
||||
gotPSKID := !bytes.Equal(pskID, defaultPSKID)
|
||||
|
||||
switch {
|
||||
case gotPSK != gotPSKID:
|
||||
return fmt.Errorf("Inconsistent PSK inputs [%d] [%v] [%v]", mode, gotPSK, gotPSKID)
|
||||
case gotPSK && !pskMode[mode]:
|
||||
return fmt.Errorf("PSK input provided when not needed [%d]", mode)
|
||||
case !gotPSK && pskMode[mode]:
|
||||
return fmt.Errorf("Missing required PSK input [%d]", mode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type hpkeContext struct {
|
||||
mode Mode
|
||||
pskIDHash []byte `tls:"head=none"`
|
||||
infoHash []byte `tls:"head=none"`
|
||||
}
|
||||
|
||||
type contextParameters struct {
|
||||
suite CipherSuite
|
||||
keyScheduleContext []byte
|
||||
secret []byte
|
||||
}
|
||||
|
||||
func (cp contextParameters) aeadKey() []byte {
|
||||
return cp.suite.KDF.LabeledExpand(cp.secret, cp.suite.ID(), "key", cp.keyScheduleContext, cp.suite.AEAD.KeySize())
|
||||
}
|
||||
|
||||
func (cp contextParameters) exporterSecret() []byte {
|
||||
return cp.suite.KDF.LabeledExpand(cp.secret, cp.suite.ID(), "exp", cp.keyScheduleContext, cp.suite.KDF.OutputSize())
|
||||
}
|
||||
|
||||
func (cp contextParameters) aeadBaseNonce() []byte {
|
||||
return cp.suite.KDF.LabeledExpand(cp.secret, cp.suite.ID(), "base_nonce", cp.keyScheduleContext, cp.suite.AEAD.NonceSize())
|
||||
}
|
||||
|
||||
type setupParameters struct {
|
||||
sharedSecret []byte
|
||||
enc []byte
|
||||
}
|
||||
|
||||
func keySchedule(suite CipherSuite, mode Mode, sharedSecret, info, psk, pskID []byte) (contextParameters, error) {
|
||||
err := verifyPSKInputs(suite, mode, psk, pskID)
|
||||
if err != nil {
|
||||
return contextParameters{}, err
|
||||
}
|
||||
|
||||
suiteID := suite.ID()
|
||||
pskIDHash := suite.KDF.LabeledExtract(nil, suiteID, "psk_id_hash", pskID)
|
||||
infoHash := suite.KDF.LabeledExtract(nil, suiteID, "info_hash", info)
|
||||
|
||||
contextStruct := hpkeContext{mode, pskIDHash, infoHash}
|
||||
keyScheduleContext, err := syntax.Marshal(contextStruct)
|
||||
if err != nil {
|
||||
return contextParameters{}, err
|
||||
}
|
||||
|
||||
secret := suite.KDF.LabeledExtract(sharedSecret, suiteID, "secret", psk)
|
||||
|
||||
params := contextParameters{
|
||||
suite: suite,
|
||||
keyScheduleContext: keyScheduleContext,
|
||||
secret: secret,
|
||||
}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
// contextRole specifies the role of a party in possession of a Context: if
|
||||
// equal to `contextRoleSender`, then the party is the sender; if equal to
|
||||
// `contextRoleReceiver`, then the party is the receiver.
|
||||
type contextRole uint8
|
||||
|
||||
const (
|
||||
contextRoleSender contextRole = 0x00
|
||||
contextRoleReceiver contextRole = 0x01
|
||||
)
|
||||
|
||||
// context represents an HPKE context encoded on the wire.
|
||||
type context struct {
|
||||
// Marshaled fields
|
||||
Role contextRole
|
||||
KEMID KEMID
|
||||
KDFID KDFID
|
||||
AEADID AEADID
|
||||
ExporterSecret []byte `tls:"head=1"`
|
||||
Key []byte `tls:"head=1"`
|
||||
BaseNonce []byte `tls:"head=1"`
|
||||
Seq uint64
|
||||
|
||||
// Operational structures
|
||||
aead cipher.AEAD `tls:"omit"`
|
||||
suite CipherSuite `tls:"omit"`
|
||||
|
||||
// Historical record
|
||||
nonces [][]byte `tls:"omit"`
|
||||
setupParams setupParameters `tls:"omit"`
|
||||
contextParams contextParameters `tls:"omit"`
|
||||
}
|
||||
|
||||
func newContext(role contextRole, suite CipherSuite, setupParams setupParameters, contextParams contextParameters) (context, error) {
|
||||
key := contextParams.aeadKey()
|
||||
baseNonce := contextParams.aeadBaseNonce()
|
||||
exporterSecret := contextParams.exporterSecret()
|
||||
|
||||
aead, err := suite.AEAD.New(key)
|
||||
if err != nil {
|
||||
return context{}, err
|
||||
}
|
||||
|
||||
ctx := context{
|
||||
Role: role,
|
||||
KEMID: suite.KEM.ID(),
|
||||
KDFID: suite.KDF.ID(),
|
||||
AEADID: suite.AEAD.ID(),
|
||||
ExporterSecret: exporterSecret,
|
||||
Key: key,
|
||||
BaseNonce: baseNonce,
|
||||
Seq: 0,
|
||||
aead: aead,
|
||||
suite: suite,
|
||||
setupParams: setupParams,
|
||||
contextParams: contextParams,
|
||||
}
|
||||
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func unmarshalContext(role contextRole, opaque []byte) (context, error) {
|
||||
var ctx context
|
||||
var err error
|
||||
if _, err = syntax.Unmarshal(opaque, &ctx); err != nil {
|
||||
return context{}, err
|
||||
}
|
||||
|
||||
if ctx.Role != role {
|
||||
return context{}, fmt.Errorf("role mismatch")
|
||||
}
|
||||
|
||||
ctx.suite, err = AssembleCipherSuite(ctx.KEMID, ctx.KDFID, ctx.AEADID)
|
||||
if err != nil {
|
||||
return context{}, err
|
||||
}
|
||||
|
||||
// Construct AEAD and validate the key length.
|
||||
ctx.aead, err = ctx.suite.AEAD.New(ctx.Key)
|
||||
if err != nil {
|
||||
return context{}, err
|
||||
}
|
||||
|
||||
// Validate the nonce length.
|
||||
if len(ctx.BaseNonce) != ctx.aead.NonceSize() {
|
||||
return context{}, fmt.Errorf("base nonce length: got %d; want %d", len(ctx.BaseNonce), ctx.aead.NonceSize())
|
||||
}
|
||||
|
||||
// Validate the exporter secret length.
|
||||
if len(ctx.ExporterSecret) != ctx.suite.KDF.OutputSize() {
|
||||
return context{}, fmt.Errorf("exporter secret length: got %d; want %d", len(ctx.ExporterSecret), ctx.suite.KDF.OutputSize())
|
||||
}
|
||||
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (ctx *context) computeNonce() []byte {
|
||||
buf := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(buf, ctx.Seq)
|
||||
|
||||
Nn := len(ctx.BaseNonce)
|
||||
nonce := make([]byte, Nn)
|
||||
copy(nonce, ctx.BaseNonce)
|
||||
for i := range buf {
|
||||
nonce[Nn-8+i] ^= buf[i]
|
||||
}
|
||||
|
||||
ctx.nonces = append(ctx.nonces, nonce)
|
||||
return nonce
|
||||
}
|
||||
|
||||
func (ctx *context) incrementSeq() {
|
||||
ctx.Seq += 1
|
||||
if ctx.Seq == 0 {
|
||||
panic("sequence number wrapped")
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *context) Export(context []byte, L int) []byte {
|
||||
return ctx.suite.KDF.LabeledExpand(ctx.ExporterSecret, ctx.suite.ID(), "sec", context, L)
|
||||
}
|
||||
|
||||
func (ctx *context) Marshal() ([]byte, error) {
|
||||
return syntax.Marshal(ctx)
|
||||
}
|
||||
|
||||
type EncryptContext struct {
|
||||
context
|
||||
}
|
||||
|
||||
func newEncryptContext(suite CipherSuite, setupParams setupParameters, contextParams contextParameters) (*EncryptContext, error) {
|
||||
ctx, err := newContext(contextRoleSender, suite, setupParams, contextParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EncryptContext{ctx}, nil
|
||||
}
|
||||
|
||||
func (ctx *EncryptContext) Seal(aad, pt []byte) []byte {
|
||||
ct := ctx.aead.Seal(nil, ctx.computeNonce(), pt, aad)
|
||||
ctx.incrementSeq()
|
||||
return ct
|
||||
}
|
||||
|
||||
func UnmarshalEncryptContext(opaque []byte) (*EncryptContext, error) {
|
||||
ctx, err := unmarshalContext(contextRoleSender, opaque)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EncryptContext{ctx}, nil
|
||||
}
|
||||
|
||||
type DecryptContext struct {
|
||||
context
|
||||
}
|
||||
|
||||
func newDecryptContext(suite CipherSuite, setupParams setupParameters, contextParams contextParameters) (*DecryptContext, error) {
|
||||
ctx, err := newContext(contextRoleReceiver, suite, setupParams, contextParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DecryptContext{ctx}, nil
|
||||
}
|
||||
|
||||
func (ctx *DecryptContext) Open(aad, ct []byte) ([]byte, error) {
|
||||
pt, err := ctx.aead.Open(nil, ctx.computeNonce(), ct, aad)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx.incrementSeq()
|
||||
return pt, nil
|
||||
}
|
||||
|
||||
func UnmarshalDecryptContext(opaque []byte) (*DecryptContext, error) {
|
||||
ctx, err := unmarshalContext(contextRoleReceiver, opaque)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DecryptContext{ctx}, nil
|
||||
}
|
||||
|
||||
///////
|
||||
// Base
|
||||
|
||||
func SetupBaseS(suite CipherSuite, rand io.Reader, pkR KEMPublicKey, info []byte) ([]byte, *EncryptContext, error) {
|
||||
// sharedSecret, enc = Encap(pkR)
|
||||
sharedSecret, enc, err := suite.KEM.Encap(rand, pkR)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
setupParams := setupParameters{
|
||||
sharedSecret: sharedSecret,
|
||||
enc: enc,
|
||||
}
|
||||
|
||||
params, err := keySchedule(suite, modeBase, sharedSecret, info, defaultPSK(suite), defaultPSKID(suite))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ctx, err := newEncryptContext(suite, setupParams, params)
|
||||
return enc, ctx, err
|
||||
}
|
||||
|
||||
func SetupBaseR(suite CipherSuite, skR KEMPrivateKey, enc, info []byte) (*DecryptContext, error) {
|
||||
// sharedSecret = Decap(enc, skR)
|
||||
sharedSecret, err := suite.KEM.Decap(enc, skR)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
setupParams := setupParameters{
|
||||
sharedSecret: sharedSecret,
|
||||
enc: enc,
|
||||
}
|
||||
|
||||
params, err := keySchedule(suite, modeBase, sharedSecret, info, defaultPSK(suite), defaultPSKID(suite))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newDecryptContext(suite, setupParams, params)
|
||||
}
|
||||
|
||||
//////
|
||||
// PSK
|
||||
|
||||
func SetupPSKS(suite CipherSuite, rand io.Reader, pkR KEMPublicKey, psk, pskID, info []byte) ([]byte, *EncryptContext, error) {
|
||||
// sharedSecret, enc = Encap(pkR)
|
||||
sharedSecret, enc, err := suite.KEM.Encap(rand, pkR)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
setupParams := setupParameters{
|
||||
sharedSecret: sharedSecret,
|
||||
enc: enc,
|
||||
}
|
||||
|
||||
params, err := keySchedule(suite, modePSK, sharedSecret, info, psk, pskID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ctx, err := newEncryptContext(suite, setupParams, params)
|
||||
return enc, ctx, err
|
||||
}
|
||||
|
||||
func SetupPSKR(suite CipherSuite, skR KEMPrivateKey, enc, psk, pskID, info []byte) (*DecryptContext, error) {
|
||||
// sharedSecret = Decap(enc, skR)
|
||||
sharedSecret, err := suite.KEM.Decap(enc, skR)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
setupParams := setupParameters{
|
||||
sharedSecret: sharedSecret,
|
||||
enc: enc,
|
||||
}
|
||||
|
||||
params, err := keySchedule(suite, modePSK, sharedSecret, info, psk, pskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newDecryptContext(suite, setupParams, params)
|
||||
}
|
||||
|
||||
///////
|
||||
// Auth
|
||||
|
||||
func SetupAuthS(suite CipherSuite, rand io.Reader, pkR KEMPublicKey, skS KEMPrivateKey, info []byte) ([]byte, *EncryptContext, error) {
|
||||
// sharedSecret, enc = AuthEncap(pkR, skS)
|
||||
auth := suite.KEM.(AuthKEMScheme)
|
||||
sharedSecret, enc, err := auth.AuthEncap(rand, pkR, skS)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
setupParams := setupParameters{
|
||||
sharedSecret: sharedSecret,
|
||||
enc: enc,
|
||||
}
|
||||
|
||||
params, err := keySchedule(suite, modeAuth, sharedSecret, info, defaultPSK(suite), defaultPSKID(suite))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ctx, err := newEncryptContext(suite, setupParams, params)
|
||||
return enc, ctx, err
|
||||
}
|
||||
|
||||
func SetupAuthR(suite CipherSuite, skR KEMPrivateKey, pkS KEMPublicKey, enc, info []byte) (*DecryptContext, error) {
|
||||
// sharedSecret = AuthDecap(enc, skR, pkS)
|
||||
auth := suite.KEM.(AuthKEMScheme)
|
||||
sharedSecret, err := auth.AuthDecap(enc, skR, pkS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
setupParams := setupParameters{
|
||||
sharedSecret: sharedSecret,
|
||||
enc: enc,
|
||||
}
|
||||
|
||||
params, err := keySchedule(suite, modeAuth, sharedSecret, info, defaultPSK(suite), defaultPSKID(suite))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newDecryptContext(suite, setupParams, params)
|
||||
}
|
||||
|
||||
/////////////
|
||||
// PSK + Auth
|
||||
|
||||
func SetupAuthPSKS(suite CipherSuite, rand io.Reader, pkR KEMPublicKey, skS KEMPrivateKey, psk, pskID, info []byte) ([]byte, *EncryptContext, error) {
|
||||
// sharedSecret, enc = AuthEncap(pkR, skS)
|
||||
auth := suite.KEM.(AuthKEMScheme)
|
||||
sharedSecret, enc, err := auth.AuthEncap(rand, pkR, skS)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
setupParams := setupParameters{
|
||||
sharedSecret: sharedSecret,
|
||||
enc: enc,
|
||||
}
|
||||
|
||||
params, err := keySchedule(suite, modeAuthPSK, sharedSecret, info, psk, pskID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ctx, err := newEncryptContext(suite, setupParams, params)
|
||||
return enc, ctx, err
|
||||
}
|
||||
|
||||
func SetupAuthPSKR(suite CipherSuite, skR KEMPrivateKey, pkS KEMPublicKey, enc, psk, pskID, info []byte) (*DecryptContext, error) {
|
||||
// sharedSecret = AuthDecap(enc, skR, pkS)
|
||||
auth := suite.KEM.(AuthKEMScheme)
|
||||
sharedSecret, err := auth.AuthDecap(enc, skR, pkS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
setupParams := setupParameters{
|
||||
sharedSecret: sharedSecret,
|
||||
enc: enc,
|
||||
}
|
||||
|
||||
params, err := keySchedule(suite, modeAuthPSK, sharedSecret, info, psk, pskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newDecryptContext(suite, setupParams, params)
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,15 @@
|
|||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
|
@ -0,0 +1,25 @@
|
|||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2020, Cisco Systems
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. 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.
|
||||
|
||||
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 HOLDER 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.
|
|
@ -0,0 +1,105 @@
|
|||
[](https://coveralls.io/github/cisco/go-tls-syntax)
|
||||
|
||||
TLS Syntax
|
||||
==========
|
||||
|
||||
TLS defines [its own syntax](https://tlswg.github.io/tls13-spec/#rfc.section.3)
|
||||
for describing structures used in that protocol. To facilitate the reuse of
|
||||
this serialization format in other context, this module maps that syntax to
|
||||
the Go structure syntax, taking advantage of Go's type annotations to encode
|
||||
non-type information carried in the TLS presentation format.
|
||||
|
||||
For example, in the TLS specification, a ClientHello message has the following
|
||||
structure:
|
||||
|
||||
~~~~~
|
||||
uint16 ProtocolVersion;
|
||||
opaque Random[32];
|
||||
uint8 CipherSuite[2];
|
||||
enum { server_name(0), ... (65535)} ExtensionType;
|
||||
|
||||
struct {
|
||||
ExtensionType extension_type;
|
||||
opaque extension_data<0..2^16-1>;
|
||||
} Extension;
|
||||
|
||||
struct {
|
||||
ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */
|
||||
Random random;
|
||||
opaque legacy_session_id<0..32>;
|
||||
CipherSuite cipher_suites<2..2^16-2>;
|
||||
opaque legacy_compression_methods<1..2^8-1>;
|
||||
Extension extensions<0..2^16-1>;
|
||||
} ClientHello;
|
||||
~~~~~
|
||||
|
||||
This maps to the following Go type definitions:
|
||||
|
||||
~~~~~
|
||||
type protocolVersion uint16
|
||||
type random [32]byte
|
||||
type cipherSuite uint16 // or [2]byte
|
||||
|
||||
type ExtensionType uint16
|
||||
|
||||
const (
|
||||
ExtensionTypeServerName ExtensionType = 0
|
||||
// ...
|
||||
)
|
||||
|
||||
type Extension struct {
|
||||
ExtensionType ExtensionType
|
||||
ExtensionData []byte `tls:"head=2"`
|
||||
}
|
||||
|
||||
type ClientHello struct {
|
||||
LegacyVersion ProtocolVersion
|
||||
Random Random
|
||||
LegacySessionID []byte `tls:"head=1,max=32"`
|
||||
CipherSuites []CipherSuite `tls:"head=2,min=2"`
|
||||
LegacyCompressionMethods []byte `tls:"head=1,min=1"`
|
||||
Extensions []Extension `tls:"head=2"`
|
||||
}
|
||||
~~~~~
|
||||
|
||||
Then you can just declare, marshal, and unmarshal structs just like you would
|
||||
with, say JSON.
|
||||
|
||||
The available annotations are as follows (with supported types noted):
|
||||
|
||||
* `omit`: Do not encode/decode this field (for: any)
|
||||
* `head=n`: Encode the length header as an `n`-byte integer (for: slice)
|
||||
* `head=varint`: Encode the length header as a [QUIC-style
|
||||
varint](https://tools.ietf.org/html/draft-ietf-quic-transport-27#section-16)
|
||||
(for: slice)
|
||||
* `head=none`: Omit the length header on encode; consume the remainder of the
|
||||
buffer on decode (for: slice)
|
||||
* `min`: The minimum length of the vector, in bytes (for: slice)
|
||||
* `max`: The maximum length of the vector, in bytes (for: slice)
|
||||
* `varint`: Encode the value as a QUIC-style varint (for:
|
||||
uint8, uint16, uint32, uint64)
|
||||
* `optional`: Encode a pointer value as an [MLS-style
|
||||
optional](https://github.com/mlswg/mls-protocol/blob/master/draft-ietf-mls-protocol.md#tree-hashes)
|
||||
(for: pointer)
|
||||
|
||||
The `Marshaler` and `Unmarshaler` interfaces play the same role as in
|
||||
`encoding/json`, i.e., they let the type define its own encoding directly. The
|
||||
`Validator` interface allows a type to define validation rules to be applied
|
||||
when marshaling or unmarshaling. The latter is especially helpful for `enum`
|
||||
values.
|
||||
|
||||
## Not supported
|
||||
|
||||
* The `select()` syntax for creating alternate version of the same struct (see,
|
||||
e.g., the KeyShare extension)
|
||||
|
||||
* The backreference syntax for array lengths or select parameters, as in `opaque
|
||||
fragment[TLSPlaintext.length]`. Note, however, that in cases where the length
|
||||
immediately preceds the array, these can be reframed as vectors with
|
||||
appropriate sizes.
|
||||
|
||||
## History
|
||||
|
||||
This code was originally part of the [mint](https://github.com/bifurcation/mint)
|
||||
TLS 1.3 stack, and has been moved to this repository with the agreement of the
|
||||
contributors. Please see that repo for history before the move.
|
|
@ -0,0 +1,456 @@
|
|||
package syntax
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func Unmarshal(data []byte, v interface{}) (int, error) {
|
||||
// Check for well-formedness.
|
||||
// Avoids filling out half a data structure
|
||||
// before discovering a JSON syntax error.
|
||||
d := decodeState{}
|
||||
d.Write(data)
|
||||
return d.unmarshal(v)
|
||||
}
|
||||
|
||||
// Unmarshaler is the interface implemented by types that can
|
||||
// unmarshal a TLS description of themselves. Note that unlike the
|
||||
// JSON unmarshaler interface, it is not known a priori how much of
|
||||
// the input data will be consumed. So the Unmarshaler must state
|
||||
// how much of the input data it consumed.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalTLS([]byte) (int, error)
|
||||
}
|
||||
|
||||
type decodeState struct {
|
||||
bytes.Buffer
|
||||
}
|
||||
|
||||
func (d *decodeState) unmarshal(v interface{}) (read int, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if _, ok := r.(runtime.Error); ok {
|
||||
panic(r)
|
||||
}
|
||||
if s, ok := r.(string); ok {
|
||||
panic(s)
|
||||
}
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr || rv.IsNil() {
|
||||
return 0, fmt.Errorf("Invalid unmarshal target (non-pointer or nil)")
|
||||
}
|
||||
|
||||
read = d.value(rv)
|
||||
return read, nil
|
||||
}
|
||||
|
||||
func (e *decodeState) value(v reflect.Value) int {
|
||||
return valueDecoder(v)(e, v, fieldOptions{})
|
||||
}
|
||||
|
||||
type decoderFunc func(e *decodeState, v reflect.Value, opts fieldOptions) int
|
||||
|
||||
func valueDecoder(v reflect.Value) decoderFunc {
|
||||
return typeDecoder(v.Type().Elem())
|
||||
}
|
||||
|
||||
var decoderCache sync.Map // map[reflect.Type]decoderFunc
|
||||
|
||||
func typeDecoder(t reflect.Type) decoderFunc {
|
||||
if fi, ok := decoderCache.Load(t); ok {
|
||||
return fi.(decoderFunc)
|
||||
}
|
||||
|
||||
// XXX(RLB): Wait group based support for recursive types omitted
|
||||
|
||||
// Compute the real decoder and replace the indirect func with it.
|
||||
f := newTypeDecoder(t)
|
||||
decoderCache.Store(t, f)
|
||||
return f
|
||||
}
|
||||
|
||||
var (
|
||||
unmarshalerType = reflect.TypeOf(new(Unmarshaler)).Elem()
|
||||
uint8Type = reflect.TypeOf(uint8(0))
|
||||
)
|
||||
|
||||
func newTypeDecoder(t reflect.Type) decoderFunc {
|
||||
var dec decoderFunc
|
||||
if t.Kind() != reflect.Ptr && reflect.PtrTo(t).Implements(unmarshalerType) {
|
||||
dec = unmarshalerDecoder
|
||||
} else {
|
||||
switch t.Kind() {
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
dec = uintDecoder
|
||||
case reflect.Array:
|
||||
dec = newArrayDecoder(t)
|
||||
case reflect.Slice:
|
||||
dec = newSliceDecoder(t)
|
||||
case reflect.Map:
|
||||
dec = newMapDecoder(t)
|
||||
case reflect.Struct:
|
||||
dec = newStructDecoder(t)
|
||||
case reflect.Ptr:
|
||||
dec = newPointerDecoder(t)
|
||||
default:
|
||||
panic(fmt.Errorf("Unsupported type (%s)", t))
|
||||
}
|
||||
}
|
||||
|
||||
if reflect.PtrTo(t).Implements(validatorType) {
|
||||
dec = newValidatorDecoder(dec)
|
||||
}
|
||||
|
||||
return dec
|
||||
}
|
||||
|
||||
///// Specific decoders below
|
||||
|
||||
func omitDecoder(d *decodeState, v reflect.Value, opts fieldOptions) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
func unmarshalerDecoder(d *decodeState, v reflect.Value, opts fieldOptions) int {
|
||||
um, ok := v.Interface().(Unmarshaler)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("Non-Unmarshaler passed to unmarshalerEncoder"))
|
||||
}
|
||||
|
||||
read, err := um.UnmarshalTLS(d.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if read > d.Len() {
|
||||
panic(fmt.Errorf("Invalid return value from UnmarshalTLS"))
|
||||
}
|
||||
|
||||
d.Next(read)
|
||||
return read
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
func newValidatorDecoder(raw decoderFunc) decoderFunc {
|
||||
return func(d *decodeState, v reflect.Value, opts fieldOptions) int {
|
||||
read := raw(d, v, opts)
|
||||
|
||||
val, ok := v.Interface().(Validator)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("Non-Validator passed to validatorDecoder"))
|
||||
}
|
||||
|
||||
if err := val.ValidForTLS(); err != nil {
|
||||
panic(fmt.Errorf("Decoded invalid TLS value: %v", err))
|
||||
}
|
||||
|
||||
return read
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
func uintDecoder(d *decodeState, v reflect.Value, opts fieldOptions) int {
|
||||
if opts.varint {
|
||||
return varintDecoder(d, v, opts)
|
||||
}
|
||||
|
||||
uintLen := int(v.Elem().Type().Size())
|
||||
buf := d.Next(uintLen)
|
||||
if len(buf) != uintLen {
|
||||
panic(fmt.Errorf("Insufficient data to read uint"))
|
||||
}
|
||||
|
||||
return setUintFromBuffer(v, buf)
|
||||
}
|
||||
|
||||
func varintDecoder(d *decodeState, v reflect.Value, opts fieldOptions) int {
|
||||
l, val := readVarint(d)
|
||||
|
||||
uintLen := int(v.Elem().Type().Size())
|
||||
if uintLen < l {
|
||||
panic(fmt.Errorf("Uint too small to fit varint: %d < %d", uintLen, l))
|
||||
}
|
||||
|
||||
v.Elem().SetUint(val)
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func readVarint(d *decodeState) (int, uint64) {
|
||||
// Read the first octet and decide the size of the presented varint
|
||||
first := d.Next(1)
|
||||
if len(first) != 1 {
|
||||
panic(fmt.Errorf("Insufficient data to read varint length"))
|
||||
}
|
||||
|
||||
twoBits := uint(first[0] >> 6)
|
||||
varintLen := 1 << twoBits
|
||||
|
||||
rest := d.Next(varintLen - 1)
|
||||
if len(rest) != varintLen-1 {
|
||||
panic(fmt.Errorf("Insufficient data to read varint"))
|
||||
}
|
||||
|
||||
buf := append(first, rest...)
|
||||
buf[0] &= 0x3f
|
||||
|
||||
return len(buf), decodeUintFromBuffer(buf)
|
||||
}
|
||||
|
||||
func decodeUintFromBuffer(buf []byte) uint64 {
|
||||
val := uint64(0)
|
||||
for _, b := range buf {
|
||||
val = (val << 8) + uint64(b)
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
func setUintFromBuffer(v reflect.Value, buf []byte) int {
|
||||
v.Elem().SetUint(decodeUintFromBuffer(buf))
|
||||
return len(buf)
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type arrayDecoder struct {
|
||||
elemDec decoderFunc
|
||||
}
|
||||
|
||||
func (ad *arrayDecoder) decode(d *decodeState, v reflect.Value, opts fieldOptions) int {
|
||||
n := v.Elem().Type().Len()
|
||||
read := 0
|
||||
for i := 0; i < n; i += 1 {
|
||||
read += ad.elemDec(d, v.Elem().Index(i).Addr(), opts)
|
||||
}
|
||||
return read
|
||||
}
|
||||
|
||||
func newArrayDecoder(t reflect.Type) decoderFunc {
|
||||
dec := &arrayDecoder{typeDecoder(t.Elem())}
|
||||
return dec.decode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
func decodeLength(d *decodeState, opts fieldOptions) (int, int) {
|
||||
read := 0
|
||||
length := 0
|
||||
switch {
|
||||
case opts.omitHeader:
|
||||
read = 0
|
||||
length = d.Len()
|
||||
|
||||
case opts.varintHeader:
|
||||
var length64 uint64
|
||||
read, length64 = readVarint(d)
|
||||
length = int(length64)
|
||||
|
||||
case opts.headerSize > 0:
|
||||
lengthBytes := d.Next(int(opts.headerSize))
|
||||
if len(lengthBytes) != int(opts.headerSize) {
|
||||
panic(fmt.Errorf("Not enough data to read header"))
|
||||
}
|
||||
read = len(lengthBytes)
|
||||
length = int(decodeUintFromBuffer(lengthBytes))
|
||||
|
||||
default:
|
||||
panic(fmt.Errorf("Cannot decode a slice without a header length"))
|
||||
}
|
||||
|
||||
// Check that the length is OK
|
||||
if opts.maxSize > 0 && length > opts.maxSize {
|
||||
panic(fmt.Errorf("Length of vector exceeds declared max"))
|
||||
}
|
||||
if length < opts.minSize {
|
||||
panic(fmt.Errorf("Length of vector below declared min"))
|
||||
}
|
||||
|
||||
return read, length
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type sliceDecoder struct {
|
||||
elementType reflect.Type
|
||||
elementDec decoderFunc
|
||||
}
|
||||
|
||||
func (sd *sliceDecoder) decode(d *decodeState, v reflect.Value, opts fieldOptions) int {
|
||||
// Determine the length of the vector
|
||||
read, length := decodeLength(d, opts)
|
||||
|
||||
// Decode elements
|
||||
elemData := d.Next(length)
|
||||
if len(elemData) != length {
|
||||
panic(fmt.Errorf("Not enough data to read elements"))
|
||||
}
|
||||
|
||||
// For opaque values, we can return a reference instead of making a new slice
|
||||
if v.Elem().Type().Elem() == uint8Type {
|
||||
v.Elem().Set(reflect.ValueOf(elemData))
|
||||
return read + length
|
||||
}
|
||||
|
||||
// For other values, we need to decode the raw data
|
||||
elemBuf := &decodeState{}
|
||||
elemBuf.Write(elemData)
|
||||
elems := []reflect.Value{}
|
||||
for elemBuf.Len() > 0 {
|
||||
elem := reflect.New(sd.elementType)
|
||||
read += sd.elementDec(elemBuf, elem, opts)
|
||||
elems = append(elems, elem)
|
||||
}
|
||||
|
||||
v.Elem().Set(reflect.MakeSlice(v.Elem().Type(), len(elems), len(elems)))
|
||||
for i := 0; i < len(elems); i += 1 {
|
||||
v.Elem().Index(i).Set(elems[i].Elem())
|
||||
}
|
||||
return read
|
||||
}
|
||||
|
||||
func newSliceDecoder(t reflect.Type) decoderFunc {
|
||||
dec := &sliceDecoder{
|
||||
elementType: t.Elem(),
|
||||
elementDec: typeDecoder(t.Elem()),
|
||||
}
|
||||
return dec.decode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type mapDecoder struct {
|
||||
keyType reflect.Type
|
||||
valType reflect.Type
|
||||
keyDec decoderFunc
|
||||
valDec decoderFunc
|
||||
}
|
||||
|
||||
func (md mapDecoder) decode(d *decodeState, v reflect.Value, opts fieldOptions) int {
|
||||
// Determine the length of the data
|
||||
read, length := decodeLength(d, opts)
|
||||
|
||||
// Decode key/value pairs
|
||||
elemData := d.Next(length)
|
||||
if len(elemData) != length {
|
||||
panic(fmt.Errorf("Not enough data to read elements"))
|
||||
}
|
||||
|
||||
mapType := reflect.MapOf(md.keyType, md.valType)
|
||||
v.Elem().Set(reflect.MakeMap(mapType))
|
||||
|
||||
nullOpts := fieldOptions{}
|
||||
elemBuf := &decodeState{}
|
||||
elemBuf.Write(elemData)
|
||||
for elemBuf.Len() > 0 {
|
||||
key := reflect.New(md.keyType)
|
||||
read += md.keyDec(elemBuf, key, nullOpts)
|
||||
|
||||
val := reflect.New(md.valType)
|
||||
read += md.valDec(elemBuf, val, nullOpts)
|
||||
|
||||
v.Elem().SetMapIndex(key.Elem(), val.Elem())
|
||||
}
|
||||
|
||||
return read
|
||||
}
|
||||
|
||||
func newMapDecoder(t reflect.Type) decoderFunc {
|
||||
md := mapDecoder{
|
||||
keyType: t.Key(),
|
||||
valType: t.Elem(),
|
||||
keyDec: typeDecoder(t.Key()),
|
||||
valDec: typeDecoder(t.Elem()),
|
||||
}
|
||||
|
||||
return md.decode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type structDecoder struct {
|
||||
fieldOpts []fieldOptions
|
||||
fieldDecs []decoderFunc
|
||||
}
|
||||
|
||||
func (sd *structDecoder) decode(d *decodeState, v reflect.Value, opts fieldOptions) int {
|
||||
read := 0
|
||||
for i := range sd.fieldDecs {
|
||||
read += sd.fieldDecs[i](d, v.Elem().Field(i).Addr(), sd.fieldOpts[i])
|
||||
}
|
||||
return read
|
||||
}
|
||||
|
||||
func newStructDecoder(t reflect.Type) decoderFunc {
|
||||
n := t.NumField()
|
||||
sd := structDecoder{
|
||||
fieldOpts: make([]fieldOptions, n),
|
||||
fieldDecs: make([]decoderFunc, n),
|
||||
}
|
||||
|
||||
for i := 0; i < n; i += 1 {
|
||||
f := t.Field(i)
|
||||
|
||||
tag := f.Tag.Get("tls")
|
||||
opts := parseTag(tag)
|
||||
|
||||
if !opts.ValidForType(f.Type) {
|
||||
panic(fmt.Errorf("Tags invalid for field type"))
|
||||
}
|
||||
|
||||
sd.fieldOpts[i] = opts
|
||||
if sd.fieldOpts[i].omit {
|
||||
sd.fieldDecs[i] = omitDecoder
|
||||
} else {
|
||||
sd.fieldDecs[i] = typeDecoder(f.Type)
|
||||
}
|
||||
}
|
||||
|
||||
return sd.decode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type pointerDecoder struct {
|
||||
base decoderFunc
|
||||
}
|
||||
|
||||
func (pd *pointerDecoder) decode(d *decodeState, v reflect.Value, opts fieldOptions) int {
|
||||
readBase := 0
|
||||
if opts.optional {
|
||||
readBase = 1
|
||||
flag := d.Next(1)
|
||||
switch flag[0] {
|
||||
case optionalFlagAbsent:
|
||||
indir := v.Elem()
|
||||
indir.Set(reflect.Zero(indir.Type()))
|
||||
return 1
|
||||
|
||||
case optionalFlagPresent:
|
||||
// No action; continue as normal
|
||||
|
||||
default:
|
||||
panic(fmt.Errorf("Invalid flag byte for optional: [%x]", flag))
|
||||
}
|
||||
}
|
||||
|
||||
v.Elem().Set(reflect.New(v.Elem().Type().Elem()))
|
||||
return readBase + pd.base(d, v.Elem(), opts)
|
||||
}
|
||||
|
||||
func newPointerDecoder(t reflect.Type) decoderFunc {
|
||||
baseDecoder := typeDecoder(t.Elem())
|
||||
pd := pointerDecoder{base: baseDecoder}
|
||||
return pd.decode
|
||||
}
|
|
@ -0,0 +1,411 @@
|
|||
package syntax
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
e := &encodeState{}
|
||||
err := e.marshal(v, fieldOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
|
||||
// Marshaler is the interface implemented by types that
|
||||
// have a defined TLS encoding.
|
||||
type Marshaler interface {
|
||||
MarshalTLS() ([]byte, error)
|
||||
}
|
||||
|
||||
type encodeState struct {
|
||||
bytes.Buffer
|
||||
}
|
||||
|
||||
func (e *encodeState) marshal(v interface{}, opts fieldOptions) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if _, ok := r.(runtime.Error); ok {
|
||||
panic(r)
|
||||
}
|
||||
if s, ok := r.(string); ok {
|
||||
panic(s)
|
||||
}
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
e.reflectValue(reflect.ValueOf(v), opts)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *encodeState) reflectValue(v reflect.Value, opts fieldOptions) {
|
||||
valueEncoder(v)(e, v, opts)
|
||||
}
|
||||
|
||||
type encoderFunc func(e *encodeState, v reflect.Value, opts fieldOptions)
|
||||
|
||||
func valueEncoder(v reflect.Value) encoderFunc {
|
||||
if !v.IsValid() {
|
||||
panic(fmt.Errorf("Cannot encode an invalid value"))
|
||||
}
|
||||
return typeEncoder(v.Type())
|
||||
}
|
||||
|
||||
var encoderCache sync.Map // map[reflect.Type]encoderFunc
|
||||
|
||||
func typeEncoder(t reflect.Type) encoderFunc {
|
||||
if fi, ok := encoderCache.Load(t); ok {
|
||||
return fi.(encoderFunc)
|
||||
}
|
||||
|
||||
// XXX(RLB): Wait group based support for recursive types omitted
|
||||
|
||||
// Compute the real encoder and replace the indirect func with it.
|
||||
f := newTypeEncoder(t)
|
||||
encoderCache.Store(t, f)
|
||||
return f
|
||||
}
|
||||
|
||||
var (
|
||||
marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
|
||||
)
|
||||
|
||||
func newTypeEncoder(t reflect.Type) encoderFunc {
|
||||
var enc encoderFunc
|
||||
if t.Implements(marshalerType) {
|
||||
enc = marshalerEncoder
|
||||
} else {
|
||||
switch t.Kind() {
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
enc = uintEncoder
|
||||
case reflect.Array:
|
||||
enc = newArrayEncoder(t)
|
||||
case reflect.Slice:
|
||||
enc = newSliceEncoder(t)
|
||||
case reflect.Struct:
|
||||
enc = newStructEncoder(t)
|
||||
case reflect.Map:
|
||||
enc = newMapEncoder(t)
|
||||
case reflect.Ptr:
|
||||
enc = newPointerEncoder(t)
|
||||
default:
|
||||
panic(fmt.Errorf("Unsupported type (%s)", t))
|
||||
}
|
||||
}
|
||||
|
||||
if t.Implements(validatorType) {
|
||||
enc = newValidatorEncoder(enc)
|
||||
}
|
||||
|
||||
return enc
|
||||
}
|
||||
|
||||
///// Specific encoders below
|
||||
|
||||
func omitEncoder(e *encodeState, v reflect.Value, opts fieldOptions) {
|
||||
// This space intentionally left blank
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
func marshalerEncoder(e *encodeState, v reflect.Value, opts fieldOptions) {
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() && !opts.optional {
|
||||
panic(fmt.Errorf("Cannot encode nil pointer"))
|
||||
}
|
||||
|
||||
if v.Kind() == reflect.Ptr && opts.optional {
|
||||
if v.IsNil() {
|
||||
writeUint(e, uint64(optionalFlagAbsent), 1)
|
||||
return
|
||||
}
|
||||
|
||||
writeUint(e, uint64(optionalFlagPresent), 1)
|
||||
}
|
||||
|
||||
m, ok := v.Interface().(Marshaler)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("Non-Marshaler passed to marshalerEncoder"))
|
||||
}
|
||||
|
||||
b, err := m.MarshalTLS()
|
||||
if err == nil {
|
||||
_, err = e.Write(b)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
func newValidatorEncoder(raw encoderFunc) encoderFunc {
|
||||
return func(e *encodeState, v reflect.Value, opts fieldOptions) {
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
// Cannot validate nil values; just pass through to encoder
|
||||
raw(e, v, opts)
|
||||
return
|
||||
}
|
||||
|
||||
val, ok := v.Interface().(Validator)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("Non-Validator passed to validatorEncoder"))
|
||||
}
|
||||
|
||||
if err := val.ValidForTLS(); err != nil {
|
||||
panic(fmt.Errorf("Invalid TLS value: %v", err))
|
||||
}
|
||||
|
||||
raw(e, v, opts)
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
func uintEncoder(e *encodeState, v reflect.Value, opts fieldOptions) {
|
||||
if opts.varint {
|
||||
varintEncoder(e, v, opts)
|
||||
return
|
||||
}
|
||||
|
||||
writeUint(e, v.Uint(), int(v.Type().Size()))
|
||||
}
|
||||
|
||||
func varintEncoder(e *encodeState, v reflect.Value, opts fieldOptions) {
|
||||
writeVarint(e, v.Uint())
|
||||
}
|
||||
|
||||
func writeVarint(e *encodeState, u uint64) {
|
||||
if (u >> 62) > 0 {
|
||||
panic(fmt.Errorf("uint value is too big for varint"))
|
||||
}
|
||||
|
||||
var varintLen int
|
||||
for _, len := range []uint{1, 2, 4, 8} {
|
||||
if u < (uint64(1) << (8*len - 2)) {
|
||||
varintLen = int(len)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
twoBits := map[int]uint64{1: 0x00, 2: 0x01, 4: 0x02, 8: 0x03}[varintLen]
|
||||
shift := uint(8*varintLen - 2)
|
||||
writeUint(e, u|(twoBits<<shift), varintLen)
|
||||
}
|
||||
|
||||
func writeUint(e *encodeState, u uint64, len int) {
|
||||
for i := 0; i < len; i += 1 {
|
||||
e.WriteByte(byte(u >> uint(8*(len-i-1))))
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type arrayEncoder struct {
|
||||
elemEnc encoderFunc
|
||||
}
|
||||
|
||||
func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts fieldOptions) {
|
||||
n := v.Len()
|
||||
for i := 0; i < n; i += 1 {
|
||||
ae.elemEnc(e, v.Index(i), opts)
|
||||
}
|
||||
}
|
||||
|
||||
func newArrayEncoder(t reflect.Type) encoderFunc {
|
||||
enc := &arrayEncoder{typeEncoder(t.Elem())}
|
||||
return enc.encode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
func encodeLength(e *encodeState, n int, opts fieldOptions) {
|
||||
if opts.maxSize > 0 && n > opts.maxSize {
|
||||
panic(fmt.Errorf("Encoded length more than max [%d > %d]", n, opts.maxSize))
|
||||
}
|
||||
if n < opts.minSize {
|
||||
panic(fmt.Errorf("Encoded length less than min [%d < %d]", n, opts.minSize))
|
||||
}
|
||||
|
||||
switch {
|
||||
case opts.omitHeader:
|
||||
// None.
|
||||
|
||||
case opts.varintHeader:
|
||||
writeVarint(e, uint64(n))
|
||||
|
||||
case opts.headerSize > 0:
|
||||
if n>>uint(8*opts.headerSize) > 0 {
|
||||
panic(fmt.Errorf("Encoded length too long for header length [%d, %d]", n, opts.headerSize))
|
||||
}
|
||||
|
||||
writeUint(e, uint64(n), int(opts.headerSize))
|
||||
|
||||
default:
|
||||
panic(fmt.Errorf("Cannot encode a slice without a header length"))
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type sliceEncoder struct {
|
||||
ae *arrayEncoder
|
||||
}
|
||||
|
||||
func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts fieldOptions) {
|
||||
arrayState := &encodeState{}
|
||||
se.ae.encode(arrayState, v, opts)
|
||||
|
||||
encodeLength(e, arrayState.Len(), opts)
|
||||
e.Write(arrayState.Bytes())
|
||||
}
|
||||
|
||||
func newSliceEncoder(t reflect.Type) encoderFunc {
|
||||
enc := &sliceEncoder{&arrayEncoder{typeEncoder(t.Elem())}}
|
||||
return enc.encode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type structEncoder struct {
|
||||
fieldOpts []fieldOptions
|
||||
fieldEncs []encoderFunc
|
||||
}
|
||||
|
||||
func (se *structEncoder) encode(e *encodeState, v reflect.Value, opts fieldOptions) {
|
||||
for i := range se.fieldEncs {
|
||||
se.fieldEncs[i](e, v.Field(i), se.fieldOpts[i])
|
||||
}
|
||||
}
|
||||
|
||||
func newStructEncoder(t reflect.Type) encoderFunc {
|
||||
n := t.NumField()
|
||||
se := structEncoder{
|
||||
fieldOpts: make([]fieldOptions, n),
|
||||
fieldEncs: make([]encoderFunc, n),
|
||||
}
|
||||
|
||||
for i := 0; i < n; i += 1 {
|
||||
f := t.Field(i)
|
||||
tag := f.Tag.Get("tls")
|
||||
opts := parseTag(tag)
|
||||
|
||||
if !opts.ValidForType(f.Type) {
|
||||
panic(fmt.Errorf("Tags invalid for field type"))
|
||||
}
|
||||
|
||||
se.fieldOpts[i] = opts
|
||||
if opts.omit {
|
||||
se.fieldEncs[i] = omitEncoder
|
||||
} else {
|
||||
se.fieldEncs[i] = typeEncoder(f.Type)
|
||||
}
|
||||
}
|
||||
|
||||
return se.encode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type mapEncoder struct {
|
||||
keyEnc encoderFunc
|
||||
valEnc encoderFunc
|
||||
}
|
||||
|
||||
type encMap struct {
|
||||
keyEncs [][]byte
|
||||
valEncs [][]byte
|
||||
}
|
||||
|
||||
func (em encMap) Len() int { return len(em.keyEncs) }
|
||||
|
||||
func (em *encMap) Swap(i, j int) {
|
||||
em.keyEncs[i], em.keyEncs[j] = em.keyEncs[j], em.keyEncs[i]
|
||||
em.valEncs[i], em.valEncs[j] = em.valEncs[j], em.valEncs[i]
|
||||
}
|
||||
|
||||
func (em encMap) Less(i, j int) bool {
|
||||
return bytes.Compare(em.keyEncs[i], em.keyEncs[j]) < 0
|
||||
}
|
||||
|
||||
func (em encMap) Size() int {
|
||||
size := 0
|
||||
for i := range em.keyEncs {
|
||||
size += len(em.keyEncs[i]) + len(em.valEncs[i])
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func (em encMap) Encode(e *encodeState) {
|
||||
for i := range em.keyEncs {
|
||||
e.Write(em.keyEncs[i])
|
||||
e.Write(em.valEncs[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (me *mapEncoder) encode(e *encodeState, v reflect.Value, opts fieldOptions) {
|
||||
enc := &encMap{
|
||||
keyEncs: make([][]byte, v.Len()),
|
||||
valEncs: make([][]byte, v.Len()),
|
||||
}
|
||||
nullOpts := fieldOptions{}
|
||||
it := v.MapRange()
|
||||
for i := 0; i < enc.Len() && it.Next(); i++ {
|
||||
keyState := &encodeState{}
|
||||
me.keyEnc(keyState, it.Key(), nullOpts)
|
||||
enc.keyEncs[i] = keyState.Bytes()
|
||||
|
||||
valState := &encodeState{}
|
||||
me.valEnc(valState, it.Value(), nullOpts)
|
||||
enc.valEncs[i] = valState.Bytes()
|
||||
}
|
||||
|
||||
sort.Sort(enc)
|
||||
|
||||
encodeLength(e, enc.Size(), opts)
|
||||
enc.Encode(e)
|
||||
}
|
||||
|
||||
func newMapEncoder(t reflect.Type) encoderFunc {
|
||||
me := mapEncoder{
|
||||
keyEnc: typeEncoder(t.Key()),
|
||||
valEnc: typeEncoder(t.Elem()),
|
||||
}
|
||||
|
||||
return me.encode
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
type pointerEncoder struct {
|
||||
base encoderFunc
|
||||
}
|
||||
|
||||
func (pe pointerEncoder) encode(e *encodeState, v reflect.Value, opts fieldOptions) {
|
||||
if v.IsNil() && !opts.optional {
|
||||
panic(fmt.Errorf("Cannot encode nil pointer"))
|
||||
}
|
||||
|
||||
if opts.optional {
|
||||
if v.IsNil() {
|
||||
writeUint(e, uint64(optionalFlagAbsent), 1)
|
||||
return
|
||||
}
|
||||
|
||||
writeUint(e, uint64(optionalFlagPresent), 1)
|
||||
}
|
||||
|
||||
pe.base(e, v.Elem(), opts)
|
||||
}
|
||||
|
||||
func newPointerEncoder(t reflect.Type) encoderFunc {
|
||||
baseEncoder := typeEncoder(t.Elem())
|
||||
pe := pointerEncoder{base: baseEncoder}
|
||||
return pe.encode
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module github.com/cisco/go-tls-syntax
|
||||
|
||||
go 1.14
|
||||
|
||||
require github.com/stretchr/testify v1.6.1
|
|
@ -0,0 +1,10 @@
|
|||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -0,0 +1,37 @@
|
|||
name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
if [ -f Gopkg.toml ]; then
|
||||
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||
dep ensure
|
||||
fi
|
||||
|
||||
- name: Build
|
||||
run: go build -v .
|
||||
|
||||
- name: Test
|
||||
run: go test -v .
|
|
@ -0,0 +1,76 @@
|
|||
package syntax
|
||||
|
||||
///
|
||||
/// Write Stream
|
||||
///
|
||||
|
||||
type WriteStream struct {
|
||||
buffer []byte
|
||||
}
|
||||
|
||||
func NewWriteStream() *WriteStream {
|
||||
return &WriteStream{}
|
||||
}
|
||||
|
||||
func (s *WriteStream) Data() []byte {
|
||||
return s.buffer
|
||||
}
|
||||
|
||||
func (s *WriteStream) Write(val interface{}) error {
|
||||
enc, err := Marshal(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.buffer = append(s.buffer, enc...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *WriteStream) WriteAll(vals ...interface{}) error {
|
||||
for _, val := range vals {
|
||||
err := s.Write(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
///
|
||||
/// ReadStream
|
||||
///
|
||||
|
||||
type ReadStream struct {
|
||||
buffer []byte
|
||||
cursor int
|
||||
}
|
||||
|
||||
func NewReadStream(data []byte) *ReadStream {
|
||||
return &ReadStream{data, 0}
|
||||
}
|
||||
|
||||
func (s *ReadStream) Read(val interface{}) (int, error) {
|
||||
read, err := Unmarshal(s.buffer[s.cursor:], val)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
s.cursor += read
|
||||
return read, nil
|
||||
}
|
||||
|
||||
func (s *ReadStream) ReadAll(vals ...interface{}) (int, error) {
|
||||
read := 0
|
||||
for _, val := range vals {
|
||||
readHere, err := s.Read(val)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
read += readHere
|
||||
}
|
||||
return read, nil
|
||||
}
|
||||
|
||||
func (s *ReadStream) Position() int {
|
||||
return s.cursor
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
package syntax
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Allow types to mark themselves as valid for TLS to marshal/unmarshal
|
||||
type Validator interface {
|
||||
ValidForTLS() error
|
||||
}
|
||||
|
||||
var (
|
||||
validatorType = reflect.TypeOf(new(Validator)).Elem()
|
||||
)
|
||||
|
||||
// `tls:"head=2,min=2,max=255,varint"`
|
||||
|
||||
type fieldOptions struct {
|
||||
omitHeader bool // whether to omit the slice header
|
||||
varintHeader bool // whether to encode the header length as a varint
|
||||
headerSize int // length of length in bytes
|
||||
minSize int // minimum vector size in bytes
|
||||
maxSize int // maximum vector size in bytes
|
||||
|
||||
varint bool // whether to encode as a varint
|
||||
optional bool // whether to encode pointer as optional
|
||||
omit bool // whether to skip a field
|
||||
}
|
||||
|
||||
func mutuallyExclusive(vals []bool) bool {
|
||||
set := 0
|
||||
for _, val := range vals {
|
||||
if val {
|
||||
set += 1
|
||||
}
|
||||
}
|
||||
return set <= 1
|
||||
}
|
||||
|
||||
func (opts fieldOptions) Consistent() bool {
|
||||
// No more than one of the header options must be set
|
||||
headerPaths := []bool{opts.omitHeader, opts.varintHeader, opts.headerSize > 1}
|
||||
if !mutuallyExclusive(headerPaths) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Max must be greater than min
|
||||
if opts.maxSize > 0 && opts.minSize > opts.maxSize {
|
||||
return false
|
||||
}
|
||||
|
||||
// varint and optional are mutually exclusive with each other, and with the slice options
|
||||
headerOpts := (opts.omitHeader || opts.varintHeader || opts.headerSize > 1 || opts.maxSize > 0 || opts.minSize > 0)
|
||||
encodePaths := []bool{headerOpts, opts.varint, opts.optional}
|
||||
if !mutuallyExclusive(encodePaths) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Omit is mutually exclusive with everything else
|
||||
otherThanOmit := (headerOpts || opts.varint || opts.optional)
|
||||
if !mutuallyExclusive([]bool{opts.omit, otherThanOmit}) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (opts fieldOptions) ValidForType(t reflect.Type) bool {
|
||||
headerType := t.Kind() == reflect.Slice || t.Kind() == reflect.Map
|
||||
headerTags := opts.omitHeader || opts.varintHeader || (opts.headerSize != 0) ||
|
||||
(opts.minSize != 0) || (opts.maxSize != 0)
|
||||
if headerTags && !headerType {
|
||||
return false
|
||||
}
|
||||
|
||||
uintRequired := opts.varint
|
||||
if uintRequired {
|
||||
switch t.Kind() {
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
ptrRequired := opts.optional
|
||||
if ptrRequired && t.Kind() != reflect.Ptr {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var (
|
||||
varintOption = "varint"
|
||||
optionalOption = "optional"
|
||||
omitOption = "omit"
|
||||
|
||||
headOptionNone = "none"
|
||||
headOptionVarint = "varint"
|
||||
headValueNoHead = uint(255)
|
||||
headValueVarint = uint(254)
|
||||
|
||||
optionalFlagAbsent uint8 = 0
|
||||
optionalFlagPresent uint8 = 1
|
||||
)
|
||||
|
||||
func atoi(a string) int {
|
||||
i, err := strconv.Atoi(a)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Invalid header size: %v", err))
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// parseTag parses a struct field's "tls" tag as a comma-separated list of
|
||||
// name=value pairs, where the values MUST be unsigned integers, or in
|
||||
// the special case of head, "none" or "varint"
|
||||
func parseTag(tag string) fieldOptions {
|
||||
opts := fieldOptions{}
|
||||
for _, token := range strings.Split(tag, ",") {
|
||||
parts := strings.Split(token, "=")
|
||||
|
||||
// Handle name-only entries
|
||||
if len(parts) == 1 {
|
||||
switch parts[0] {
|
||||
case varintOption:
|
||||
opts.varint = true
|
||||
case optionalOption:
|
||||
opts.optional = true
|
||||
case omitOption:
|
||||
opts.omit = true
|
||||
default:
|
||||
// XXX(rlb): Ignoring unknown fields
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if len(parts) != 2 || len(parts[0]) == 0 || len(parts[1]) == 0 {
|
||||
panic(fmt.Errorf("Malformed tag"))
|
||||
}
|
||||
|
||||
// Handle name=value entries
|
||||
switch parts[0] {
|
||||
case "head":
|
||||
switch {
|
||||
case parts[1] == headOptionNone:
|
||||
opts.omitHeader = true
|
||||
case parts[1] == headOptionVarint:
|
||||
opts.varintHeader = true
|
||||
default:
|
||||
opts.headerSize = atoi(parts[1])
|
||||
}
|
||||
|
||||
case "min":
|
||||
opts.minSize = atoi(parts[1])
|
||||
|
||||
case "max":
|
||||
opts.maxSize = atoi(parts[1])
|
||||
|
||||
default:
|
||||
// XXX(rlb): Ignoring unknown fields
|
||||
}
|
||||
}
|
||||
|
||||
if !opts.Consistent() {
|
||||
panic(fmt.Errorf("Inconsistent options"))
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
Copyright (c) 2019 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.
|
||||
|
||||
========================================================================
|
||||
|
||||
Copyright (c) 2009 The Go Authors. 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 Google Inc. 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.
|
|
@ -0,0 +1,30 @@
|
|||
// Package sidh provides implementation of experimental post-quantum
|
||||
// Supersingular Isogeny Diffie-Hellman (SIDH) as well as Supersingular
|
||||
// Isogeny Key Encapsulation (SIKE).
|
||||
//
|
||||
// It comes with implementations of 2 different field arithmetic
|
||||
// implementations sidh.Fp503 and sidh.Fp751.
|
||||
//
|
||||
// | Algoirthm | Public Key Size | Shared Secret Size | Ciphertext Size |
|
||||
// |-----------|-----------------|--------------------|-----------------|
|
||||
// | SIDH/p503 | 376 | 126 | N/A |
|
||||
// | SIDH/p751 | 564 | 188 | N/A |
|
||||
// | SIKE/p503 | 376 | 16 | 402 |
|
||||
// | SIKE/p751 | 564 | 24 | 596 |
|
||||
//
|
||||
// In order to instantiate SIKE/p751 KEM one needs to create a KEM object
|
||||
// and allocate internal structures. This can be done with NewSike751 helper.
|
||||
// After that kem can be used multiple times.
|
||||
//
|
||||
// var kem = sike.NewSike751(rand.Reader)
|
||||
// kem.Encapsulate(ciphertext, sharedSecret, publicBob)
|
||||
// kem.Decapsulate(sharedSecret, privateBob, PublicBob, ciphertext)
|
||||
//
|
||||
// Code is optimized for AMD64 and aarch64. Generic implementation
|
||||
// is provided for other architectures.
|
||||
//
|
||||
// References:
|
||||
// - [SIDH] https://eprint.iacr.org/2011/506
|
||||
// - [SIKE] http://www.sike.org/files/SIDH-spec.pdf
|
||||
//
|
||||
package sidh
|
|
@ -0,0 +1,2 @@
|
|||
// Package common provides types, variables, constants and functions commonly used in SIDH or SIKE.
|
||||
package common
|
24
vendor/github.com/cloudflare/circl/dh/sidh/internal/common/params.go
generated
vendored
Normal file
24
vendor/github.com/cloudflare/circl/dh/sidh/internal/common/params.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
package common
|
||||
|
||||
import "fmt"
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
// Registers SIDH parameters for particular field.
|
||||
func Register(id uint8, p *SidhParams) {
|
||||
if _, ok := sidhParams[id]; ok {
|
||||
msg := fmt.Sprintf("sidh: Field with id %d already registered", id)
|
||||
panic(msg)
|
||||
}
|
||||
sidhParams[id] = *p
|
||||
}
|
103
vendor/github.com/cloudflare/circl/dh/sidh/internal/common/types.go
generated
vendored
Normal file
103
vendor/github.com/cloudflare/circl/dh/sidh/internal/common/types.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
package common
|
||||
|
||||
const (
|
||||
// corresponds to words in P751
|
||||
FpMaxWords = 12
|
||||
// corresponds to byte size of P751 SIDH private key for B
|
||||
MaxSidhPrivateKeyBsz = 48
|
||||
// corresponds to byte size of P751 SIKE private key for B
|
||||
MaxSikePrivateKeyBsz = MaxSidhPrivateKeyBsz + MaxMsgBsz
|
||||
// corresponds to SIKE max length of 'n' (see 1.4 of SIKE spec in NIST PQC round 1)
|
||||
MaxMsgBsz = 40
|
||||
// corresponds to byte size of shared secret generated by SIKEp751
|
||||
MaxSharedSecretBsz = 188
|
||||
// correponds to by size of the P751 public key
|
||||
MaxPublicKeySz = 3 * FpMaxWords * 64
|
||||
// correponds to by size of the ciphertext produced by SIKE/P751
|
||||
MaxCiphertextBsz = MaxMsgBsz + MaxPublicKeySz
|
||||
)
|
||||
|
||||
// Id's correspond to bitlength of the prime field characteristic
|
||||
// Currently Fp751 is the only one supported by this implementation
|
||||
const (
|
||||
Fp503 uint8 = iota
|
||||
Fp751
|
||||
)
|
||||
|
||||
// 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 Fp [FpMaxWords]uint64
|
||||
|
||||
// Represents an intermediate product of two elements of the base field F_p.
|
||||
type FpX2 [2 * FpMaxWords]uint64
|
||||
|
||||
// Represents an element of the extended field Fp^2 = Fp(x+i)
|
||||
type Fp2 struct {
|
||||
A Fp
|
||||
B Fp
|
||||
}
|
||||
|
||||
type DomainParams struct {
|
||||
// P, Q and R=P-Q base points
|
||||
AffineP, AffineQ, AffineR Fp2
|
||||
// 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 int
|
||||
// 2- and 3-torsion group parameter definitions
|
||||
A, B DomainParams
|
||||
// Precomputed identity element in the Fp2 in Montgomery domain
|
||||
OneFp2 Fp2
|
||||
// Precomputed 1/2 in the Fp2 in Montgomery domain
|
||||
HalfFp2 Fp2
|
||||
// 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 int
|
||||
// Length of SIKE ephemeral KEM key (see [SIKE], 1.4 and 5.1)
|
||||
KemSize int
|
||||
// Byte size of ciphertext that KEM produces
|
||||
CiphertextSize int
|
||||
}
|
||||
|
||||
// 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 Fp2
|
||||
C Fp2
|
||||
}
|
||||
|
||||
// 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 Fp2
|
||||
Z Fp2
|
||||
}
|
||||
|
||||
// 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 Fp2
|
||||
C Fp2
|
||||
}
|
46
vendor/github.com/cloudflare/circl/dh/sidh/internal/common/utils.go
generated
vendored
Normal file
46
vendor/github.com/cloudflare/circl/dh/sidh/internal/common/utils.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
package common
|
||||
|
||||
// Constant time select.
|
||||
// if pick == 1 (out = in1)
|
||||
// if pick == 0 (out = in2)
|
||||
// else out is undefined
|
||||
func Cpick(pick int, out, in1, in2 []byte) {
|
||||
var which = byte((int8(pick << 7)) >> 7)
|
||||
for i := range out {
|
||||
out[i] = (in1[i] & which) | (in2[i] & ^which)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 BytesToFp2(fp2 *Fp2, input []byte, bytelen int) {
|
||||
if len(input) < 2*bytelen {
|
||||
panic("input byte slice too short")
|
||||
}
|
||||
|
||||
for i := 0; i < bytelen; i++ {
|
||||
j := i / 8
|
||||
k := uint64(i % 8)
|
||||
fp2.A[j] |= uint64(input[i]) << (8 * k)
|
||||
fp2.B[j] |= uint64(input[i+bytelen]) << (8 * k)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the input to wire format.
|
||||
//
|
||||
// The output byte slice must be at least 2*bytelen(p) bytes long.
|
||||
func Fp2ToBytes(output []byte, fp2 *Fp2, bytelen int) {
|
||||
if len(output) < 2*bytelen {
|
||||
panic("output byte slice too short")
|
||||
}
|
||||
|
||||
// convert to bytes in little endian form
|
||||
for i := 0; i < bytelen; i++ {
|
||||
// set i = j*8 + k
|
||||
tmp := i / 8
|
||||
k := uint64(i % 8)
|
||||
output[i] = byte(fp2.A[tmp] >> (8 * k))
|
||||
output[i+bytelen] = byte(fp2.B[tmp] >> (8 * k))
|
||||
}
|
||||
}
|
1673
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/arith_amd64.s
generated
vendored
Normal file
1673
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/arith_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
769
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/arith_arm64.s
generated
vendored
Normal file
769
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/arith_arm64.s
generated
vendored
Normal file
|
@ -0,0 +1,769 @@
|
|||
// +build arm64,!noasm
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·cswapP503(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 ·addP503(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 ·subP503(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 ·adlP503(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 ·sulP503(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 ·mulP503(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 with B = 4, w = 64
|
||||
TEXT ·rdcP503(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 ·modP503(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
|
45
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/arith_decl.go
generated
vendored
Normal file
45
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/arith_decl.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots.
|
||||
|
||||
// +build amd64,!noasm arm64,!noasm
|
||||
|
||||
package p503
|
||||
|
||||
import (
|
||||
. "github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
)
|
||||
|
||||
// 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 cswapP503(x, y *Fp, choice uint8)
|
||||
|
||||
// Compute z = x + y (mod p).
|
||||
//go:noescape
|
||||
func addP503(z, x, y *Fp)
|
||||
|
||||
// Compute z = x - y (mod p).
|
||||
//go:noescape
|
||||
func subP503(z, x, y *Fp)
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
//go:noescape
|
||||
func adlP503(z, x, y *FpX2)
|
||||
|
||||
// Compute z = x - y, without reducing mod p.
|
||||
//go:noescape
|
||||
func sulP503(z, x, y *FpX2)
|
||||
|
||||
// Reduce a field element in [0, 2*p) to one in [0,p).
|
||||
//go:noescape
|
||||
func modP503(x *Fp)
|
||||
|
||||
// Computes z = x * y.
|
||||
//go:noescape
|
||||
func mulP503(z *FpX2, x, y *Fp)
|
||||
|
||||
// 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 rdcP503(z *Fp, x *FpX2)
|
192
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/arith_generic.go
generated
vendored
Normal file
192
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/arith_generic.go
generated
vendored
Normal file
|
@ -0,0 +1,192 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots.
|
||||
|
||||
// +build noasm !amd64,!arm64
|
||||
|
||||
package p503
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
)
|
||||
|
||||
// Compute z = x + y (mod p).
|
||||
func addP503(z, x, y *common.Fp) {
|
||||
var carry uint64
|
||||
|
||||
// z=x+y % P503
|
||||
for i := 0; i < FpWords; i++ {
|
||||
z[i], carry = bits.Add64(x[i], y[i], carry)
|
||||
}
|
||||
|
||||
// z = z - P503x2
|
||||
carry = 0
|
||||
for i := 0; i < FpWords; i++ {
|
||||
z[i], carry = bits.Sub64(z[i], P503x2[i], carry)
|
||||
}
|
||||
|
||||
// if z<0 add P503x2 back
|
||||
mask := uint64(0 - carry)
|
||||
carry = 0
|
||||
for i := 0; i < FpWords; i++ {
|
||||
z[i], carry = bits.Add64(z[i], P503x2[i]&mask, carry)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute z = x - y (mod p).
|
||||
func subP503(z, x, y *common.Fp) {
|
||||
var borrow uint64
|
||||
|
||||
for i := 0; i < FpWords; i++ {
|
||||
z[i], borrow = bits.Sub64(x[i], y[i], borrow)
|
||||
}
|
||||
|
||||
mask := uint64(0 - borrow)
|
||||
borrow = 0
|
||||
|
||||
for i := 0; i < FpWords; i++ {
|
||||
z[i], borrow = bits.Add64(z[i], P503x2[i]&mask, borrow)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 cswapP503(x, y *common.Fp, mask uint8) {
|
||||
var tmp, mask64 uint64
|
||||
|
||||
mask64 = 0 - uint64(mask)
|
||||
for i := 0; i < FpWords; 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^(FpWords*64). Destroys the input value.
|
||||
func rdcP503(z *common.Fp, x *common.FpX2) {
|
||||
var carry, t, u, v uint64
|
||||
var hi, lo uint64
|
||||
var count int
|
||||
|
||||
count = P503p1Zeros
|
||||
|
||||
for i := 0; i < FpWords; i++ {
|
||||
for j := 0; j < i; j++ {
|
||||
if j < (i - count + 1) {
|
||||
hi, lo = bits.Mul64(z[j], P503p1[i-j])
|
||||
v, carry = bits.Add64(lo, v, 0)
|
||||
u, carry = bits.Add64(hi, u, carry)
|
||||
t += carry
|
||||
}
|
||||
}
|
||||
v, carry = bits.Add64(v, x[i], 0)
|
||||
u, carry = bits.Add64(u, 0, carry)
|
||||
t += carry
|
||||
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
|
||||
for i := FpWords; i < 2*FpWords-1; i++ {
|
||||
if count > 0 {
|
||||
count--
|
||||
}
|
||||
for j := i - FpWords + 1; j < FpWords; j++ {
|
||||
if j < (FpWords - count) {
|
||||
hi, lo = bits.Mul64(z[j], P503p1[i-j])
|
||||
v, carry = bits.Add64(lo, v, 0)
|
||||
u, carry = bits.Add64(hi, u, carry)
|
||||
t += carry
|
||||
}
|
||||
}
|
||||
v, carry = bits.Add64(v, x[i], 0)
|
||||
u, carry = bits.Add64(u, 0, carry)
|
||||
|
||||
t += carry
|
||||
z[i-FpWords] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
v, carry = bits.Add64(v, x[2*FpWords-1], 0)
|
||||
z[FpWords-1] = v
|
||||
}
|
||||
|
||||
// Compute z = x * y.
|
||||
func mulP503(z *common.FpX2, x, y *common.Fp) {
|
||||
var u, v, t uint64
|
||||
var hi, lo uint64
|
||||
var carry uint64
|
||||
|
||||
for i := uint64(0); i < FpWords; i++ {
|
||||
for j := uint64(0); j <= i; j++ {
|
||||
hi, lo = bits.Mul64(x[j], y[i-j])
|
||||
v, carry = bits.Add64(lo, v, 0)
|
||||
u, carry = bits.Add64(hi, u, carry)
|
||||
t += carry
|
||||
}
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
|
||||
for i := FpWords; i < (2*FpWords)-1; i++ {
|
||||
for j := i - FpWords + 1; j < FpWords; j++ {
|
||||
hi, lo = bits.Mul64(x[j], y[i-j])
|
||||
v, carry = bits.Add64(lo, v, 0)
|
||||
u, carry = bits.Add64(hi, u, carry)
|
||||
t += carry
|
||||
}
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
z[2*FpWords-1] = v
|
||||
}
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
func adlP503(z, x, y *common.FpX2) {
|
||||
var carry uint64
|
||||
for i := 0; i < 2*FpWords; i++ {
|
||||
z[i], carry = bits.Add64(x[i], y[i], carry)
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce a field element in [0, 2*p) to one in [0,p).
|
||||
func modP503(x *common.Fp) {
|
||||
var borrow, mask uint64
|
||||
for i := 0; i < FpWords; i++ {
|
||||
x[i], borrow = bits.Sub64(x[i], P503[i], borrow)
|
||||
}
|
||||
|
||||
// Sets all bits if borrow = 1
|
||||
mask = 0 - borrow
|
||||
borrow = 0
|
||||
for i := 0; i < FpWords; i++ {
|
||||
x[i], borrow = bits.Add64(x[i], P503[i]&mask, borrow)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute z = x - y, without reducing mod p.
|
||||
func sulP503(z, x, y *common.FpX2) {
|
||||
var borrow, mask uint64
|
||||
for i := 0; i < 2*FpWords; i++ {
|
||||
z[i], borrow = bits.Sub64(x[i], y[i], borrow)
|
||||
}
|
||||
|
||||
// Sets all bits if borrow = 1
|
||||
mask = 0 - borrow
|
||||
borrow = 0
|
||||
for i := FpWords; i < 2*FpWords; i++ {
|
||||
z[i], borrow = bits.Add64(z[i], P503[i-FpWords]&mask, borrow)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots.
|
||||
|
||||
package p503
|
||||
|
||||
import (
|
||||
. "github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sIdx int
|
||||
var phi isogeny4
|
||||
|
||||
cparam := CalcCurveParamsEquiv4(curve)
|
||||
strat := 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++
|
||||
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) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sIdx int
|
||||
var phi isogeny4
|
||||
|
||||
cparam := CalcCurveParamsEquiv4(curve)
|
||||
strat := 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++
|
||||
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) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sIdx int
|
||||
var phi isogeny3
|
||||
|
||||
cparam := CalcCurveParamsEquiv3(curve)
|
||||
strat := 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++
|
||||
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) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sIdx int
|
||||
var phi isogeny3
|
||||
|
||||
cparam := CalcCurveParamsEquiv3(curve)
|
||||
strat := 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++
|
||||
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. Public key is a set
|
||||
// of three x-coordinates: xP,xQ,x(P-Q), where P,Q are points on E_a(Fp2)
|
||||
func PublicKeyGenA(pub3Pt *[3]Fp2, prvBytes []byte) {
|
||||
var xPA, xQA, xRA ProjectivePoint
|
||||
var xPB, xQB, xRB, xR ProjectivePoint
|
||||
var invZP, invZQ, invZR Fp2
|
||||
var tmp ProjectiveCurveParameters
|
||||
var phi isogeny4
|
||||
|
||||
// Load points for A
|
||||
xPA = ProjectivePoint{X: params.A.AffineP, Z: params.OneFp2}
|
||||
xQA = ProjectivePoint{X: params.A.AffineQ, Z: params.OneFp2}
|
||||
xRA = ProjectivePoint{X: params.A.AffineR, Z: params.OneFp2}
|
||||
|
||||
// Load points for B
|
||||
xRB = ProjectivePoint{X: params.B.AffineR, Z: params.OneFp2}
|
||||
xQB = ProjectivePoint{X: params.B.AffineQ, Z: params.OneFp2}
|
||||
xPB = ProjectivePoint{X: params.B.AffineP, Z: params.OneFp2}
|
||||
|
||||
// Find isogeny kernel
|
||||
tmp.C = params.OneFp2
|
||||
xR = ScalarMul3Pt(&tmp, &xPA, &xQA, &xRA, params.A.SecretBitLen, prvBytes)
|
||||
|
||||
// Reset params object and travers isogeny tree
|
||||
tmp.C = params.OneFp2
|
||||
tmp.A = Fp2{}
|
||||
traverseTreePublicKeyA(&tmp, &xR, &xPB, &xQB, &xRB)
|
||||
|
||||
// Secret isogeny
|
||||
phi.GenerateCurve(&xR)
|
||||
xPA = phi.EvaluatePoint(&xPB)
|
||||
xQA = phi.EvaluatePoint(&xQB)
|
||||
xRA = phi.EvaluatePoint(&xRB)
|
||||
Fp2Batch3Inv(&xPA.Z, &xQA.Z, &xRA.Z, &invZP, &invZQ, &invZR)
|
||||
|
||||
mul(&pub3Pt[0], &xPA.X, &invZP)
|
||||
mul(&pub3Pt[1], &xQA.X, &invZQ)
|
||||
mul(&pub3Pt[2], &xRA.X, &invZR)
|
||||
}
|
||||
|
||||
// Generate a public key in the 2-torsion group. Public key is a set
|
||||
// of three x-coordinates: xP,xQ,x(P-Q), where P,Q are points on E_a(Fp2)
|
||||
func PublicKeyGenB(pub3Pt *[3]Fp2, prvBytes []byte) {
|
||||
var xPB, xQB, xRB, xR ProjectivePoint
|
||||
var xPA, xQA, xRA ProjectivePoint
|
||||
var invZP, invZQ, invZR Fp2
|
||||
var tmp ProjectiveCurveParameters
|
||||
var phi isogeny3
|
||||
|
||||
// Load points for B
|
||||
xRB = ProjectivePoint{X: params.B.AffineR, Z: params.OneFp2}
|
||||
xQB = ProjectivePoint{X: params.B.AffineQ, Z: params.OneFp2}
|
||||
xPB = ProjectivePoint{X: params.B.AffineP, Z: params.OneFp2}
|
||||
|
||||
// Load points for A
|
||||
xPA = ProjectivePoint{X: params.A.AffineP, Z: params.OneFp2}
|
||||
xQA = ProjectivePoint{X: params.A.AffineQ, Z: params.OneFp2}
|
||||
xRA = ProjectivePoint{X: params.A.AffineR, Z: params.OneFp2}
|
||||
|
||||
tmp.C = params.OneFp2
|
||||
xR = ScalarMul3Pt(&tmp, &xPB, &xQB, &xRB, params.B.SecretBitLen, prvBytes)
|
||||
|
||||
tmp.C = params.OneFp2
|
||||
tmp.A = Fp2{}
|
||||
traverseTreePublicKeyB(&tmp, &xR, &xPA, &xQA, &xRA)
|
||||
|
||||
phi.GenerateCurve(&xR)
|
||||
xPB = phi.EvaluatePoint(&xPA)
|
||||
xQB = phi.EvaluatePoint(&xQA)
|
||||
xRB = phi.EvaluatePoint(&xRA)
|
||||
Fp2Batch3Inv(&xPB.Z, &xQB.Z, &xRB.Z, &invZP, &invZQ, &invZR)
|
||||
|
||||
mul(&pub3Pt[0], &xPB.X, &invZP)
|
||||
mul(&pub3Pt[1], &xQB.X, &invZQ)
|
||||
mul(&pub3Pt[2], &xRB.X, &invZR)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Key agreement functions
|
||||
//
|
||||
|
||||
// Establishing shared keys in in 2-torsion group
|
||||
func DeriveSecretA(ss, prv []byte, pub3Pt *[3]Fp2) {
|
||||
var cparam ProjectiveCurveParameters
|
||||
var xP, xQ, xQmP ProjectivePoint
|
||||
var xR ProjectivePoint
|
||||
var phi isogeny4
|
||||
var jInv Fp2
|
||||
|
||||
// Recover curve coefficients
|
||||
cparam.C = params.OneFp2
|
||||
RecoverCoordinateA(&cparam, &pub3Pt[0], &pub3Pt[1], &pub3Pt[2])
|
||||
|
||||
// Find kernel of the morphism
|
||||
xP = ProjectivePoint{X: pub3Pt[0], Z: params.OneFp2}
|
||||
xQ = ProjectivePoint{X: pub3Pt[1], Z: params.OneFp2}
|
||||
xQmP = ProjectivePoint{X: pub3Pt[2], Z: params.OneFp2}
|
||||
xR = ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, params.A.SecretBitLen, prv)
|
||||
|
||||
// Traverse isogeny tree
|
||||
traverseTreeSharedKeyA(&cparam, &xR)
|
||||
|
||||
// Calculate j-invariant on isogeneus curve
|
||||
c := phi.GenerateCurve(&xR)
|
||||
RecoverCurveCoefficients4(&cparam, &c)
|
||||
Jinvariant(&cparam, &jInv)
|
||||
FromMontgomery(&jInv, &jInv)
|
||||
Fp2ToBytes(ss, &jInv, params.Bytelen)
|
||||
}
|
||||
|
||||
// Establishing shared keys in in 3-torsion group
|
||||
func DeriveSecretB(ss, prv []byte, pub3Pt *[3]Fp2) {
|
||||
var xP, xQ, xQmP ProjectivePoint
|
||||
var xR ProjectivePoint
|
||||
var cparam ProjectiveCurveParameters
|
||||
var phi isogeny3
|
||||
var jInv Fp2
|
||||
|
||||
// Recover curve coefficients
|
||||
cparam.C = params.OneFp2
|
||||
RecoverCoordinateA(&cparam, &pub3Pt[0], &pub3Pt[1], &pub3Pt[2])
|
||||
|
||||
// Find kernel of the morphism
|
||||
xP = ProjectivePoint{X: pub3Pt[0], Z: params.OneFp2}
|
||||
xQ = ProjectivePoint{X: pub3Pt[1], Z: params.OneFp2}
|
||||
xQmP = ProjectivePoint{X: pub3Pt[2], Z: params.OneFp2}
|
||||
xR = ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, params.B.SecretBitLen, prv)
|
||||
|
||||
// Traverse isogeny tree
|
||||
traverseTreeSharedKeyB(&cparam, &xR)
|
||||
|
||||
// Calculate j-invariant on isogeneus curve
|
||||
c := phi.GenerateCurve(&xR)
|
||||
RecoverCurveCoefficients3(&cparam, &c)
|
||||
Jinvariant(&cparam, &jInv)
|
||||
FromMontgomery(&jInv, &jInv)
|
||||
Fp2ToBytes(ss, &jInv, params.Bytelen)
|
||||
}
|
362
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/curve.go
generated
vendored
Normal file
362
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/curve.go
generated
vendored
Normal file
|
@ -0,0 +1,362 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots.
|
||||
|
||||
package p503
|
||||
|
||||
import (
|
||||
. "github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
)
|
||||
|
||||
// Stores isogeny 3 curve constants
|
||||
type isogeny3 struct {
|
||||
K1 Fp2
|
||||
K2 Fp2
|
||||
}
|
||||
|
||||
// Stores isogeny 4 curve constants
|
||||
type isogeny4 struct {
|
||||
isogeny3
|
||||
K3 Fp2
|
||||
}
|
||||
|
||||
// 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 Jinvariant(cparams *ProjectiveCurveParameters, j *Fp2) {
|
||||
var t0, t1 Fp2
|
||||
|
||||
sqr(j, &cparams.A) // j = A^2
|
||||
sqr(&t1, &cparams.C) // t1 = C^2
|
||||
add(&t0, &t1, &t1) // t0 = t1 + t1
|
||||
sub(&t0, j, &t0) // t0 = j - t0
|
||||
sub(&t0, &t0, &t1) // t0 = t0 - t1
|
||||
sub(j, &t0, &t1) // t0 = t0 - t1
|
||||
sqr(&t1, &t1) // t1 = t1^2
|
||||
mul(j, j, &t1) // j = j * t1
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
sqr(&t1, &t0) // t1 = t0^2
|
||||
mul(&t0, &t0, &t1) // t0 = t0 * t1
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
inv(j, j) // j = 1/j
|
||||
mul(j, &t0, j) // j = t0 * 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 RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2) {
|
||||
var t0, t1 Fp2
|
||||
|
||||
add(&t1, xp, xq) // t1 = Xp + Xq
|
||||
mul(&t0, xp, xq) // t0 = Xp * Xq
|
||||
mul(&curve.A, xr, &t1) // A = X(q-p) * t1
|
||||
add(&curve.A, &curve.A, &t0) // A = A + t0
|
||||
mul(&t0, &t0, xr) // t0 = t0 * X(q-p)
|
||||
sub(&curve.A, &curve.A, ¶ms.OneFp2) // A = A - 1
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
add(&t1, &t1, xr) // t1 = t1 + X(q-p)
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
sqr(&curve.A, &curve.A) // A = A^2
|
||||
inv(&t0, &t0) // t0 = 1/t0
|
||||
mul(&curve.A, &curve.A, &t0) // A = A * t0
|
||||
sub(&curve.A, &curve.A, &t1) // A = A - t1
|
||||
}
|
||||
|
||||
// Computes equivalence (A:C) ~ (A+2C : A-2C)
|
||||
func CalcCurveParamsEquiv3(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
|
||||
var coef CurveCoefficientsEquiv
|
||||
var c2 Fp2
|
||||
|
||||
add(&c2, &cparams.C, &cparams.C)
|
||||
// A24p = A+2*C
|
||||
add(&coef.A, &cparams.A, &c2)
|
||||
// A24m = A-2*C
|
||||
sub(&coef.C, &cparams.A, &c2)
|
||||
return coef
|
||||
}
|
||||
|
||||
// Computes equivalence (A:C) ~ (A+2C : 4C)
|
||||
func CalcCurveParamsEquiv4(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
|
||||
var coefEq CurveCoefficientsEquiv
|
||||
|
||||
add(&coefEq.C, &cparams.C, &cparams.C)
|
||||
// A24p = A+2C
|
||||
add(&coefEq.A, &cparams.A, &coefEq.C)
|
||||
// C24 = 4*C
|
||||
add(&coefEq.C, &coefEq.C, &coefEq.C)
|
||||
return coefEq
|
||||
}
|
||||
|
||||
// Helper function for RightToLeftLadder(). Returns A+2C / 4.
|
||||
func CalcAplus2Over4(cparams *ProjectiveCurveParameters) (ret Fp2) {
|
||||
var tmp Fp2
|
||||
|
||||
// 2C
|
||||
add(&tmp, &cparams.C, &cparams.C)
|
||||
// A+2C
|
||||
add(&ret, &cparams.A, &tmp)
|
||||
// 1/4C
|
||||
add(&tmp, &tmp, &tmp)
|
||||
inv(&tmp, &tmp)
|
||||
// A+2C/4C
|
||||
mul(&ret, &ret, &tmp)
|
||||
return
|
||||
}
|
||||
|
||||
// Recovers (A:C) curve parameters from projectively equivalent (A+2C:A-2C).
|
||||
func RecoverCurveCoefficients3(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
|
||||
add(&cparams.A, &coefEq.A, &coefEq.C)
|
||||
// cparams.A = 2*(A+2C+A-2C) = 4A
|
||||
add(&cparams.A, &cparams.A, &cparams.A)
|
||||
// cparams.C = (A+2C-A+2C) = 4C
|
||||
sub(&cparams.C, &coefEq.A, &coefEq.C)
|
||||
return
|
||||
}
|
||||
|
||||
// Recovers (A:C) curve parameters from projectively equivalent (A+2C:4C).
|
||||
func RecoverCurveCoefficients4(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
|
||||
// cparams.C = (4C)*1/2=2C
|
||||
mul(&cparams.C, &coefEq.C, ¶ms.HalfFp2)
|
||||
// cparams.A = A+2C - 2C = A
|
||||
sub(&cparams.A, &coefEq.A, &cparams.C)
|
||||
// cparams.C = 2C * 1/2 = C
|
||||
mul(&cparams.C, &cparams.C, ¶ms.HalfFp2)
|
||||
}
|
||||
|
||||
// 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 xDbladd(P, Q, QmP *ProjectivePoint, a24 *Fp2) (dblP, PaQ ProjectivePoint) {
|
||||
var t0, t1, t2 Fp2
|
||||
|
||||
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
|
||||
|
||||
add(&t0, xP, zP) // t0 = Xp+Zp
|
||||
sub(&t1, xP, zP) // t1 = Xp-Zp
|
||||
sqr(x2P, &t0) // 2P.X = t0^2
|
||||
sub(&t2, xQ, zQ) // t2 = Xq-Zq
|
||||
add(xPaQ, xQ, zQ) // Xp+q = Xq+Zq
|
||||
mul(&t0, &t0, &t2) // t0 = t0 * t2
|
||||
mul(z2P, &t1, &t1) // 2P.Z = t1 * t1
|
||||
mul(&t1, &t1, xPaQ) // t1 = t1 * Xp+q
|
||||
sub(&t2, x2P, z2P) // t2 = 2P.X - 2P.Z
|
||||
mul(x2P, x2P, z2P) // 2P.X = 2P.X * 2P.Z
|
||||
mul(xPaQ, a24, &t2) // Xp+q = A24 * t2
|
||||
sub(zPaQ, &t0, &t1) // Zp+q = t0 - t1
|
||||
add(z2P, xPaQ, z2P) // 2P.Z = Xp+q + 2P.Z
|
||||
add(xPaQ, &t0, &t1) // Xp+q = t0 + t1
|
||||
mul(z2P, z2P, &t2) // 2P.Z = 2P.Z * t2
|
||||
sqr(zPaQ, zPaQ) // Zp+q = Zp+q ^ 2
|
||||
sqr(xPaQ, xPaQ) // Xp+q = Xp+q ^ 2
|
||||
mul(zPaQ, xQmP, zPaQ) // Zp+q = Xq-p * Zp+q
|
||||
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 Pow2k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
|
||||
var t0, t1 Fp2
|
||||
|
||||
x, z := &xP.X, &xP.Z
|
||||
for i := uint32(0); i < k; i++ {
|
||||
sub(&t0, x, z) // t0 = Xp - Zp
|
||||
add(&t1, x, z) // t1 = Xp + Zp
|
||||
sqr(&t0, &t0) // t0 = t0 ^ 2
|
||||
sqr(&t1, &t1) // t1 = t1 ^ 2
|
||||
mul(z, ¶ms.C, &t0) // Z2p = C24 * t0
|
||||
mul(x, z, &t1) // X2p = Z2p * t1
|
||||
sub(&t1, &t1, &t0) // t1 = t1 - t0
|
||||
mul(&t0, ¶ms.A, &t1) // t0 = A24+ * t1
|
||||
add(z, z, &t0) // Z2p = Z2p + t0
|
||||
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 Pow3k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
|
||||
var t0, t1, t2, t3, t4, t5, t6 Fp2
|
||||
|
||||
x, z := &xP.X, &xP.Z
|
||||
for i := uint32(0); i < k; i++ {
|
||||
sub(&t0, x, z) // t0 = Xp - Zp
|
||||
sqr(&t2, &t0) // t2 = t0^2
|
||||
add(&t1, x, z) // t1 = Xp + Zp
|
||||
sqr(&t3, &t1) // t3 = t1^2
|
||||
add(&t4, &t1, &t0) // t4 = t1 + t0
|
||||
sub(&t0, &t1, &t0) // t0 = t1 - t0
|
||||
sqr(&t1, &t4) // t1 = t4^2
|
||||
sub(&t1, &t1, &t3) // t1 = t1 - t3
|
||||
sub(&t1, &t1, &t2) // t1 = t1 - t2
|
||||
mul(&t5, &t3, ¶ms.A) // t5 = t3 * A24+
|
||||
mul(&t3, &t3, &t5) // t3 = t5 * t3
|
||||
mul(&t6, &t2, ¶ms.C) // t6 = t2 * A24-
|
||||
mul(&t2, &t2, &t6) // t2 = t2 * t6
|
||||
sub(&t3, &t2, &t3) // t3 = t2 - t3
|
||||
sub(&t2, &t5, &t6) // t2 = t5 - t6
|
||||
mul(&t1, &t2, &t1) // t1 = t2 * t1
|
||||
add(&t2, &t3, &t1) // t2 = t3 + t1
|
||||
sqr(&t2, &t2) // t2 = t2^2
|
||||
mul(x, &t2, &t4) // X3p = t2 * t4
|
||||
sub(&t1, &t3, &t1) // t1 = t3 - t1
|
||||
sqr(&t1, &t1) // t1 = t1^2
|
||||
mul(z, &t1, &t0) // Z3p = t1 * t0
|
||||
}
|
||||
}
|
||||
|
||||
// Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3).
|
||||
//
|
||||
// All xi, yi must be distinct.
|
||||
func Fp2Batch3Inv(x1, x2, x3, y1, y2, y3 *Fp2) {
|
||||
var x1x2, t Fp2
|
||||
|
||||
mul(&x1x2, x1, x2) // x1*x2
|
||||
mul(&t, &x1x2, x3) // 1/(x1*x2*x3)
|
||||
inv(&t, &t)
|
||||
mul(y1, &t, x2) // 1/x1
|
||||
mul(y1, y1, x3)
|
||||
mul(y2, &t, x1) // 1/x2
|
||||
mul(y2, y2, x3)
|
||||
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 ScalarMul3Pt(cparams *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint, nbits uint, scalar []uint8) ProjectivePoint {
|
||||
var R0, R2, R1 ProjectivePoint
|
||||
aPlus2Over4 := 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
|
||||
cswap(&R1.X, &R1.Z, &R2.X, &R2.Z, swap)
|
||||
R0, R2 = xDbladd(&R0, &R2, &R1, &aPlus2Over4)
|
||||
}
|
||||
cswap(&R1.X, &R1.Z, &R2.X, &R2.Z, prevBit)
|
||||
return R1
|
||||
}
|
||||
|
||||
// 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 Fp2
|
||||
var coefEq CurveCoefficientsEquiv
|
||||
var K1, K2 = &phi.K1, &phi.K2
|
||||
|
||||
sub(K1, &p.X, &p.Z) // K1 = XP3 - ZP3
|
||||
sqr(&t0, K1) // t0 = K1^2
|
||||
add(K2, &p.X, &p.Z) // K2 = XP3 + ZP3
|
||||
sqr(&t1, K2) // t1 = K2^2
|
||||
add(&t2, &t0, &t1) // t2 = t0 + t1
|
||||
add(&t3, K1, K2) // t3 = K1 + K2
|
||||
sqr(&t3, &t3) // t3 = t3^2
|
||||
sub(&t3, &t3, &t2) // t3 = t3 - t2
|
||||
add(&t2, &t1, &t3) // t2 = t1 + t3
|
||||
add(&t3, &t3, &t0) // t3 = t3 + t0
|
||||
add(&t4, &t3, &t0) // t4 = t3 + t0
|
||||
add(&t4, &t4, &t4) // t4 = t4 + t4
|
||||
add(&t4, &t1, &t4) // t4 = t1 + t4
|
||||
mul(&coefEq.C, &t2, &t4) // A24m = t2 * t4
|
||||
add(&t4, &t1, &t2) // t4 = t1 + t2
|
||||
add(&t4, &t4, &t4) // t4 = t4 + t4
|
||||
add(&t4, &t0, &t4) // t4 = t0 + t4
|
||||
mul(&t4, &t3, &t4) // t4 = t3 * t4
|
||||
sub(&t0, &t4, &coefEq.C) // t0 = t4 - A24m
|
||||
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 Fp2
|
||||
var q ProjectivePoint
|
||||
var K1, K2 = &phi.K1, &phi.K2
|
||||
var px, pz = &p.X, &p.Z
|
||||
|
||||
add(&t0, px, pz) // t0 = XQ + ZQ
|
||||
sub(&t1, px, pz) // t1 = XQ - ZQ
|
||||
mul(&t0, K1, &t0) // t2 = K1 * t0
|
||||
mul(&t1, K2, &t1) // t1 = K2 * t1
|
||||
add(&t2, &t0, &t1) // t2 = t0 + t1
|
||||
sub(&t0, &t1, &t0) // t0 = t1 - t0
|
||||
sqr(&t2, &t2) // t2 = t2 ^ 2
|
||||
sqr(&t0, &t0) // t0 = t0 ^ 2
|
||||
mul(&q.X, px, &t2) // XQ'= XQ * t2
|
||||
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
|
||||
|
||||
sub(K2, xp4, zp4)
|
||||
add(K3, xp4, zp4)
|
||||
sqr(K1, zp4)
|
||||
add(K1, K1, K1)
|
||||
sqr(&coefEq.C, K1)
|
||||
add(K1, K1, K1)
|
||||
sqr(&coefEq.A, xp4)
|
||||
add(&coefEq.A, &coefEq.A, &coefEq.A)
|
||||
sqr(&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 Fp2
|
||||
var q = *p
|
||||
var xq, zq = &q.X, &q.Z
|
||||
var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
|
||||
|
||||
add(&t0, xq, zq)
|
||||
sub(&t1, xq, zq)
|
||||
mul(xq, &t0, K2)
|
||||
mul(zq, &t1, K3)
|
||||
mul(&t0, &t0, &t1)
|
||||
mul(&t0, &t0, K1)
|
||||
add(&t1, xq, zq)
|
||||
sub(zq, xq, zq)
|
||||
sqr(&t1, &t1)
|
||||
sqr(zq, zq)
|
||||
add(xq, &t0, &t1)
|
||||
sub(&t0, zq, &t0)
|
||||
mul(xq, xq, &t1)
|
||||
mul(zq, zq, &t0)
|
||||
return q
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
// Package p503 provides implementation of field arithmetic used in SIDH and SIKE.
|
||||
package p503
|
|
@ -0,0 +1,195 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots.
|
||||
|
||||
package p503
|
||||
|
||||
import (
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
)
|
||||
|
||||
// Montgomery multiplication. Input values must be already
|
||||
// in Montgomery domain.
|
||||
func mulP(dest, lhs, rhs *common.Fp) {
|
||||
var ab common.FpX2
|
||||
mulP503(&ab, lhs, rhs) // = a*b*R*R
|
||||
rdcP503(dest, &ab) // = a*b*R mod p
|
||||
}
|
||||
|
||||
// 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.
|
||||
// All values in Montgomery domains
|
||||
// Set dest = x^(2^k), for k >= 1, by repeated squarings.
|
||||
func p34(dest, x *common.Fp) {
|
||||
var lookup [16]common.Fp
|
||||
|
||||
// This performs sum(powStrategy) + 1 squarings and len(lookup) + len(mulStrategy)
|
||||
// multiplications.
|
||||
powStrategy := []uint8{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{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}
|
||||
initialMul := uint8(0)
|
||||
|
||||
// Precompute lookup table of odd multiples of x for window
|
||||
// size k=5.
|
||||
var xx common.Fp
|
||||
mulP(&xx, x, x)
|
||||
lookup[0] = *x
|
||||
for i := 1; i < 16; i++ {
|
||||
mulP(&lookup[i], &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]
|
||||
for i := uint8(0); i < uint8(len(powStrategy)); i++ {
|
||||
mulP(dest, dest, dest)
|
||||
for j := uint8(1); j < powStrategy[i]; j++ {
|
||||
mulP(dest, dest, dest)
|
||||
}
|
||||
mulP(dest, dest, &lookup[mulStrategy[i]])
|
||||
}
|
||||
}
|
||||
|
||||
func add(dest, lhs, rhs *common.Fp2) {
|
||||
addP503(&dest.A, &lhs.A, &rhs.A)
|
||||
addP503(&dest.B, &lhs.B, &rhs.B)
|
||||
}
|
||||
|
||||
func sub(dest, lhs, rhs *common.Fp2) {
|
||||
subP503(&dest.A, &lhs.A, &rhs.A)
|
||||
subP503(&dest.B, &lhs.B, &rhs.B)
|
||||
}
|
||||
|
||||
func mul(dest, lhs, rhs *common.Fp2) {
|
||||
var bMinA, cMinD common.Fp
|
||||
var ac, bd common.FpX2
|
||||
var adPlusBc common.FpX2
|
||||
var acMinBd common.FpX2
|
||||
|
||||
// Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b).
|
||||
//
|
||||
// (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.
|
||||
mulP503(&ac, &lhs.A, &rhs.A) // = a*c*R*R
|
||||
mulP503(&bd, &lhs.B, &rhs.B) // = b*d*R*R
|
||||
subP503(&bMinA, &lhs.B, &lhs.A) // = (b-a)*R
|
||||
subP503(&cMinD, &rhs.A, &rhs.B) // = (c-d)*R
|
||||
mulP503(&adPlusBc, &bMinA, &cMinD) // = (b-a)*(c-d)*R*R
|
||||
adlP503(&adPlusBc, &adPlusBc, &ac) // = ((b-a)*(c-d) + a*c)*R*R
|
||||
adlP503(&adPlusBc, &adPlusBc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R
|
||||
rdcP503(&dest.B, &adPlusBc) // = (a*d + b*c)*R mod p
|
||||
sulP503(&acMinBd, &ac, &bd) // = (a*c - b*d)*R*R
|
||||
rdcP503(&dest.A, &acMinBd) // = (a*c - b*d)*R mod p
|
||||
}
|
||||
|
||||
// Set dest = 1/x
|
||||
//
|
||||
// Allowed to overlap dest with x.
|
||||
//
|
||||
// Returns dest to allow chaining operations.
|
||||
func inv(dest, x *common.Fp2) {
|
||||
var e1, e2 common.FpX2
|
||||
var f1, f2 common.Fp
|
||||
|
||||
// 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.
|
||||
|
||||
mulP503(&e1, &x.A, &x.A) // = a*a*R*R
|
||||
mulP503(&e2, &x.B, &x.B) // = b*b*R*R
|
||||
adlP503(&e1, &e1, &e2) // = (a^2 + b^2)*R*R
|
||||
rdcP503(&f1, &e1) // = (a^2 + b^2)*R mod p
|
||||
// Now f1 = a^2 + b^2
|
||||
|
||||
mulP(&f2, &f1, &f1)
|
||||
p34(&f2, &f2)
|
||||
mulP(&f2, &f2, &f2)
|
||||
mulP(&f2, &f2, &f1)
|
||||
|
||||
mulP503(&e1, &x.A, &f2)
|
||||
rdcP503(&dest.A, &e1)
|
||||
|
||||
subP503(&f1, &common.Fp{}, &x.B)
|
||||
mulP503(&e1, &f1, &f2)
|
||||
rdcP503(&dest.B, &e1)
|
||||
}
|
||||
|
||||
func sqr(dest, x *common.Fp2) {
|
||||
var a2, aPlusB, aMinusB common.Fp
|
||||
var a2MinB2, ab2 common.FpX2
|
||||
|
||||
a := &x.A
|
||||
b := &x.B
|
||||
|
||||
// (a + bi)*(a + bi) = (a^2 - b^2) + 2abi.
|
||||
addP503(&a2, a, a) // = a*R + a*R = 2*a*R
|
||||
addP503(&aPlusB, a, b) // = a*R + b*R = (a+b)*R
|
||||
subP503(&aMinusB, a, b) // = a*R - b*R = (a-b)*R
|
||||
mulP503(&a2MinB2, &aPlusB, &aMinusB) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R
|
||||
mulP503(&ab2, &a2, b) // = 2*a*b*R*R
|
||||
rdcP503(&dest.A, &a2MinB2) // = (a^2 - b^2)*R mod p
|
||||
rdcP503(&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 cswap(xPx, xPz, xQx, xQz *common.Fp2, choice uint8) {
|
||||
cswapP503(&xPx.A, &xQx.A, choice)
|
||||
cswapP503(&xPx.B, &xQx.B, choice)
|
||||
cswapP503(&xPz.A, &xQz.A, choice)
|
||||
cswapP503(&xPz.B, &xQz.B, choice)
|
||||
}
|
||||
|
||||
// Converts in.A and in.B to Montgomery domain and stores
|
||||
// in 'out'
|
||||
// out.A = in.A * R mod p
|
||||
// out.B = in.B * R mod p
|
||||
// Performs v = v*R^2*R^(-1) mod p, for both in.A and in.B
|
||||
func ToMontgomery(out, in *common.Fp2) {
|
||||
var aRR common.FpX2
|
||||
|
||||
// a*R*R
|
||||
mulP503(&aRR, &in.A, &P503R2)
|
||||
// a*R mod p
|
||||
rdcP503(&out.A, &aRR)
|
||||
mulP503(&aRR, &in.B, &P503R2)
|
||||
rdcP503(&out.B, &aRR)
|
||||
}
|
||||
|
||||
// Converts in.A and in.B from Montgomery domain and stores
|
||||
// in 'out'
|
||||
// out.A = in.A mod p
|
||||
// out.B = in.B mod p
|
||||
//
|
||||
// After returning from the call 'in' is not modified.
|
||||
func FromMontgomery(out, in *common.Fp2) {
|
||||
var aR common.FpX2
|
||||
|
||||
// convert from montgomery domain
|
||||
copy(aR[:], in.A[:])
|
||||
rdcP503(&out.A, &aR) // = a mod p in [0, 2p)
|
||||
modP503(&out.A) // = a mod p in [0, p)
|
||||
for i := range aR {
|
||||
aR[i] = 0
|
||||
}
|
||||
copy(aR[:], in.B[:])
|
||||
rdcP503(&out.B, &aR)
|
||||
modP503(&out.B)
|
||||
}
|
191
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/params.go
generated
vendored
Normal file
191
vendor/github.com/cloudflare/circl/dh/sidh/internal/p503/params.go
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
package p503
|
||||
|
||||
//go:generate go run ../templates/gen.go P503
|
||||
|
||||
import (
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
const (
|
||||
// Number of uint64 limbs used to store field element
|
||||
FpWords = 8
|
||||
)
|
||||
|
||||
// P503 is a prime used by field Fp503
|
||||
var (
|
||||
// According to https://github.com/golang/go/issues/28230,
|
||||
// variables referred from the assembly must be in the same package.
|
||||
// HasBMI2 signals support for MULX which is in BMI2
|
||||
HasBMI2 = cpu.X86.HasBMI2
|
||||
// HasADXandBMI2 signals support for ADX and BMI2
|
||||
HasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX
|
||||
|
||||
// P503 is a prime used by field Fp503
|
||||
P503 = common.Fp{
|
||||
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xABFFFFFFFFFFFFFF,
|
||||
0x13085BDA2211E7A0, 0x1B9BF6C87B7E7DAF, 0x6045C6BDDA77A4D0, 0x004066F541811E1E,
|
||||
}
|
||||
|
||||
// P503x2 = 2*p503 - 1
|
||||
P503x2 = common.Fp{
|
||||
0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x57FFFFFFFFFFFFFF,
|
||||
0x2610B7B44423CF41, 0x3737ED90F6FCFB5E, 0xC08B8D7BB4EF49A0, 0x0080CDEA83023C3C,
|
||||
}
|
||||
|
||||
// P503p1 = p503 + 1
|
||||
P503p1 = common.Fp{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xAC00000000000000,
|
||||
0x13085BDA2211E7A0, 0x1B9BF6C87B7E7DAF, 0x6045C6BDDA77A4D0, 0x004066F541811E1E,
|
||||
}
|
||||
|
||||
// P503R2 = (2^512)^2 mod p
|
||||
P503R2 = common.Fp{
|
||||
0x5289A0CF641D011F, 0x9B88257189FED2B9, 0xA3B365D58DC8F17A, 0x5BC57AB6EFF168EC,
|
||||
0x9E51998BD84D4423, 0xBF8999CBAC3B5695, 0x46E9127BCE14CDB6, 0x003F6CFCE8B81771,
|
||||
}
|
||||
|
||||
// P503p1s8 = p503 + 1 left-shifted by 8, assuming little endianness
|
||||
P503p1s8 = common.Fp{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x085BDA2211E7A0AC, 0x9BF6C87B7E7DAF13, 0x45C6BDDA77A4D01B, 0x4066F541811E1E60,
|
||||
}
|
||||
|
||||
// P503p1Zeros number of 0 digits in the least significant part of P503+1
|
||||
P503p1Zeros = 3
|
||||
|
||||
params common.SidhParams
|
||||
)
|
||||
|
||||
func init() {
|
||||
params = common.SidhParams{
|
||||
ID: common.Fp503,
|
||||
// SIDH public key byte size.
|
||||
PublicKeySize: 378,
|
||||
// SIDH shared secret byte size.
|
||||
SharedSecretSize: 126,
|
||||
A: common.DomainParams{
|
||||
// The x-coordinate of PA
|
||||
AffineP: common.Fp2{
|
||||
A: common.Fp{
|
||||
0xE7EF4AA786D855AF, 0xED5758F03EB34D3B, 0x09AE172535A86AA9, 0x237B9CC07D622723,
|
||||
0xE3A284CBA4E7932D, 0x27481D9176C5E63F, 0x6A323FF55C6E71BF, 0x002ECC31A6FB8773,
|
||||
},
|
||||
B: common.Fp{
|
||||
0x64D02E4E90A620B8, 0xDAB8128537D4B9F1, 0x4BADF77B8A228F98, 0x0F5DBDF9D1FB7D1B,
|
||||
0xBEC4DB288E1A0DCC, 0xE76A8665E80675DB, 0x6D6F252E12929463, 0x003188BD1463FACC,
|
||||
},
|
||||
},
|
||||
// The x-coordinate of QA
|
||||
AffineQ: common.Fp2{
|
||||
A: common.Fp{
|
||||
0xB79D41025DE85D56, 0x0B867DA9DF169686, 0x740E5368021C827D, 0x20615D72157BF25C,
|
||||
0xFF1590013C9B9F5B, 0xC884DCADE8C16CEA, 0xEBD05E53BF724E01, 0x0032FEF8FDA5748C,
|
||||
},
|
||||
B: common.Fp{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
},
|
||||
},
|
||||
// The x-coordinate of RA = PA-QA
|
||||
AffineR: common.Fp2{
|
||||
A: common.Fp{
|
||||
0x12E2E849AA0A8006, 0x41CF47008635A1E8, 0x9CD720A70798AED7, 0x42A820B42FCF04CF,
|
||||
0x7BF9BAD32AAE88B1, 0xF619127A54090BBE, 0x1CB10D8F56408EAA, 0x001D6B54C3C0EDEB,
|
||||
},
|
||||
B: common.Fp{
|
||||
0x34DB54931CBAAC36, 0x420A18CB8DD5F0C4, 0x32008C1A48C0F44D, 0x3B3BA772B1CFD44D,
|
||||
0xA74B058FDAF13515, 0x095FC9CA7EEC17B4, 0x448E829D28F120F8, 0x00261EC3ED16A489,
|
||||
},
|
||||
},
|
||||
// Max size of secret key for 2-torsion group, corresponds to 2^e2 - 1
|
||||
SecretBitLen: 250,
|
||||
// SecretBitLen in bytes.
|
||||
SecretByteLen: uint((250 + 7) / 8),
|
||||
// 2-torsion group computation strategy
|
||||
IsogenyStrategy: []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},
|
||||
},
|
||||
B: common.DomainParams{
|
||||
// The x-coordinate of PB
|
||||
AffineP: common.Fp2{
|
||||
A: common.Fp{
|
||||
0x7EDE37F4FA0BC727, 0xF7F8EC5C8598941C, 0xD15519B516B5F5C8, 0xF6D5AC9B87A36282,
|
||||
0x7B19F105B30E952E, 0x13BD8B2025B4EBEE, 0x7B96D27F4EC579A2, 0x00140850CAB7E5DE,
|
||||
},
|
||||
B: common.Fp{
|
||||
0x7764909DAE7B7B2D, 0x578ABB16284911AB, 0x76E2BFD146A6BF4D, 0x4824044B23AA02F0,
|
||||
0x1105048912A321F3, 0xB8A2E482CF0F10C1, 0x42FF7D0BE2152085, 0x0018E599C5223352,
|
||||
},
|
||||
},
|
||||
// The x-coordinate of QB
|
||||
AffineQ: common.Fp2{
|
||||
A: common.Fp{
|
||||
0x4256C520FB388820, 0x744FD7C3BAAF0A13, 0x4B6A2DDDB12CBCB8, 0xE46826E27F427DF8,
|
||||
0xFE4A663CD505A61B, 0xD6B3A1BAF025C695, 0x7C3BB62B8FCC00BD, 0x003AFDDE4A35746C,
|
||||
},
|
||||
B: common.Fp{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
},
|
||||
},
|
||||
// The x-coordinate of RB = PB - QB
|
||||
AffineR: common.Fp2{
|
||||
A: common.Fp{
|
||||
0x75601CD1E6C0DFCB, 0x1A9007239B58F93E, 0xC1F1BE80C62107AC, 0x7F513B898F29FF08,
|
||||
0xEA0BEDFF43E1F7B2, 0x2C6D94018CBAE6D0, 0x3A430D31BCD84672, 0x000D26892ECCFE83,
|
||||
},
|
||||
B: common.Fp{
|
||||
0x1119D62AEA3007A1, 0xE3702AA4E04BAE1B, 0x9AB96F7D59F990E7, 0xF58440E8B43319C0,
|
||||
0xAF8134BEE1489775, 0xE7F7774E905192AA, 0xF54AE09308E98039, 0x001EF7A041A86112,
|
||||
},
|
||||
},
|
||||
// Size of secret key for 3-torsion group, corresponds to log_2(3^e3) - 1.
|
||||
SecretBitLen: 252,
|
||||
// SecretBitLen in bytes.
|
||||
SecretByteLen: uint((252 + 7) / 8),
|
||||
// 3-torsion group computation strategy
|
||||
IsogenyStrategy: []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},
|
||||
},
|
||||
// 1*R mod p
|
||||
OneFp2: common.Fp2{
|
||||
A: common.Fp{
|
||||
0x00000000000003F9, 0x0000000000000000, 0x0000000000000000, 0xB400000000000000,
|
||||
0x63CB1A6EA6DED2B4, 0x51689D8D667EB37D, 0x8ACD77C71AB24142, 0x0026FBAEC60F5953},
|
||||
},
|
||||
// 1/2 * R mod p
|
||||
HalfFp2: common.Fp2{
|
||||
A: common.Fp{
|
||||
0x00000000000001FC, 0x0000000000000000, 0x0000000000000000, 0xB000000000000000,
|
||||
0x3B69BB2464785D2A, 0x36824A2AF0FE9896, 0xF5899F427A94F309, 0x0033B15203C83BB8},
|
||||
},
|
||||
MsgLen: 24,
|
||||
// SIKEp503 provides 128 bit of classical security ([SIKE], 5.1)
|
||||
KemSize: 16,
|
||||
// ceil(503+7/8)
|
||||
Bytelen: 63,
|
||||
CiphertextSize: 16 + 8 + 378,
|
||||
}
|
||||
|
||||
common.Register(common.Fp503, ¶ms)
|
||||
}
|
2573
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/arith_amd64.s
generated
vendored
Normal file
2573
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/arith_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1478
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/arith_arm64.s
generated
vendored
Normal file
1478
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/arith_arm64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
45
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/arith_decl.go
generated
vendored
Normal file
45
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/arith_decl.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots.
|
||||
|
||||
// +build amd64,!noasm arm64,!noasm
|
||||
|
||||
package p751
|
||||
|
||||
import (
|
||||
. "github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
)
|
||||
|
||||
// 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 cswapP751(x, y *Fp, choice uint8)
|
||||
|
||||
// Compute z = x + y (mod p).
|
||||
//go:noescape
|
||||
func addP751(z, x, y *Fp)
|
||||
|
||||
// Compute z = x - y (mod p).
|
||||
//go:noescape
|
||||
func subP751(z, x, y *Fp)
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
//go:noescape
|
||||
func adlP751(z, x, y *FpX2)
|
||||
|
||||
// Compute z = x - y, without reducing mod p.
|
||||
//go:noescape
|
||||
func sulP751(z, x, y *FpX2)
|
||||
|
||||
// Reduce a field element in [0, 2*p) to one in [0,p).
|
||||
//go:noescape
|
||||
func modP751(x *Fp)
|
||||
|
||||
// Computes z = x * y.
|
||||
//go:noescape
|
||||
func mulP751(z *FpX2, x, y *Fp)
|
||||
|
||||
// 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 rdcP751(z *Fp, x *FpX2)
|
192
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/arith_generic.go
generated
vendored
Normal file
192
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/arith_generic.go
generated
vendored
Normal file
|
@ -0,0 +1,192 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots.
|
||||
|
||||
// +build noasm !amd64,!arm64
|
||||
|
||||
package p751
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
)
|
||||
|
||||
// Compute z = x + y (mod p).
|
||||
func addP751(z, x, y *common.Fp) {
|
||||
var carry uint64
|
||||
|
||||
// z=x+y % P751
|
||||
for i := 0; i < FpWords; i++ {
|
||||
z[i], carry = bits.Add64(x[i], y[i], carry)
|
||||
}
|
||||
|
||||
// z = z - P751x2
|
||||
carry = 0
|
||||
for i := 0; i < FpWords; i++ {
|
||||
z[i], carry = bits.Sub64(z[i], P751x2[i], carry)
|
||||
}
|
||||
|
||||
// if z<0 add P751x2 back
|
||||
mask := uint64(0 - carry)
|
||||
carry = 0
|
||||
for i := 0; i < FpWords; i++ {
|
||||
z[i], carry = bits.Add64(z[i], P751x2[i]&mask, carry)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute z = x - y (mod p).
|
||||
func subP751(z, x, y *common.Fp) {
|
||||
var borrow uint64
|
||||
|
||||
for i := 0; i < FpWords; i++ {
|
||||
z[i], borrow = bits.Sub64(x[i], y[i], borrow)
|
||||
}
|
||||
|
||||
mask := uint64(0 - borrow)
|
||||
borrow = 0
|
||||
|
||||
for i := 0; i < FpWords; i++ {
|
||||
z[i], borrow = bits.Add64(z[i], P751x2[i]&mask, borrow)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 cswapP751(x, y *common.Fp, mask uint8) {
|
||||
var tmp, mask64 uint64
|
||||
|
||||
mask64 = 0 - uint64(mask)
|
||||
for i := 0; i < FpWords; 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^(FpWords*64). Destroys the input value.
|
||||
func rdcP751(z *common.Fp, x *common.FpX2) {
|
||||
var carry, t, u, v uint64
|
||||
var hi, lo uint64
|
||||
var count int
|
||||
|
||||
count = P751p1Zeros
|
||||
|
||||
for i := 0; i < FpWords; i++ {
|
||||
for j := 0; j < i; j++ {
|
||||
if j < (i - count + 1) {
|
||||
hi, lo = bits.Mul64(z[j], P751p1[i-j])
|
||||
v, carry = bits.Add64(lo, v, 0)
|
||||
u, carry = bits.Add64(hi, u, carry)
|
||||
t += carry
|
||||
}
|
||||
}
|
||||
v, carry = bits.Add64(v, x[i], 0)
|
||||
u, carry = bits.Add64(u, 0, carry)
|
||||
t += carry
|
||||
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
|
||||
for i := FpWords; i < 2*FpWords-1; i++ {
|
||||
if count > 0 {
|
||||
count--
|
||||
}
|
||||
for j := i - FpWords + 1; j < FpWords; j++ {
|
||||
if j < (FpWords - count) {
|
||||
hi, lo = bits.Mul64(z[j], P751p1[i-j])
|
||||
v, carry = bits.Add64(lo, v, 0)
|
||||
u, carry = bits.Add64(hi, u, carry)
|
||||
t += carry
|
||||
}
|
||||
}
|
||||
v, carry = bits.Add64(v, x[i], 0)
|
||||
u, carry = bits.Add64(u, 0, carry)
|
||||
|
||||
t += carry
|
||||
z[i-FpWords] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
v, carry = bits.Add64(v, x[2*FpWords-1], 0)
|
||||
z[FpWords-1] = v
|
||||
}
|
||||
|
||||
// Compute z = x * y.
|
||||
func mulP751(z *common.FpX2, x, y *common.Fp) {
|
||||
var u, v, t uint64
|
||||
var hi, lo uint64
|
||||
var carry uint64
|
||||
|
||||
for i := uint64(0); i < FpWords; i++ {
|
||||
for j := uint64(0); j <= i; j++ {
|
||||
hi, lo = bits.Mul64(x[j], y[i-j])
|
||||
v, carry = bits.Add64(lo, v, 0)
|
||||
u, carry = bits.Add64(hi, u, carry)
|
||||
t += carry
|
||||
}
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
|
||||
for i := FpWords; i < (2*FpWords)-1; i++ {
|
||||
for j := i - FpWords + 1; j < FpWords; j++ {
|
||||
hi, lo = bits.Mul64(x[j], y[i-j])
|
||||
v, carry = bits.Add64(lo, v, 0)
|
||||
u, carry = bits.Add64(hi, u, carry)
|
||||
t += carry
|
||||
}
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
z[2*FpWords-1] = v
|
||||
}
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
func adlP751(z, x, y *common.FpX2) {
|
||||
var carry uint64
|
||||
for i := 0; i < 2*FpWords; i++ {
|
||||
z[i], carry = bits.Add64(x[i], y[i], carry)
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce a field element in [0, 2*p) to one in [0,p).
|
||||
func modP751(x *common.Fp) {
|
||||
var borrow, mask uint64
|
||||
for i := 0; i < FpWords; i++ {
|
||||
x[i], borrow = bits.Sub64(x[i], P751[i], borrow)
|
||||
}
|
||||
|
||||
// Sets all bits if borrow = 1
|
||||
mask = 0 - borrow
|
||||
borrow = 0
|
||||
for i := 0; i < FpWords; i++ {
|
||||
x[i], borrow = bits.Add64(x[i], P751[i]&mask, borrow)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute z = x - y, without reducing mod p.
|
||||
func sulP751(z, x, y *common.FpX2) {
|
||||
var borrow, mask uint64
|
||||
for i := 0; i < 2*FpWords; i++ {
|
||||
z[i], borrow = bits.Sub64(x[i], y[i], borrow)
|
||||
}
|
||||
|
||||
// Sets all bits if borrow = 1
|
||||
mask = 0 - borrow
|
||||
borrow = 0
|
||||
for i := FpWords; i < 2*FpWords; i++ {
|
||||
z[i], borrow = bits.Add64(z[i], P751[i-FpWords]&mask, borrow)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots.
|
||||
|
||||
package p751
|
||||
|
||||
import (
|
||||
. "github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sIdx int
|
||||
var phi isogeny4
|
||||
|
||||
cparam := CalcCurveParamsEquiv4(curve)
|
||||
strat := 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++
|
||||
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) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sIdx int
|
||||
var phi isogeny4
|
||||
|
||||
cparam := CalcCurveParamsEquiv4(curve)
|
||||
strat := 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++
|
||||
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) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sIdx int
|
||||
var phi isogeny3
|
||||
|
||||
cparam := CalcCurveParamsEquiv3(curve)
|
||||
strat := 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++
|
||||
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) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sIdx int
|
||||
var phi isogeny3
|
||||
|
||||
cparam := CalcCurveParamsEquiv3(curve)
|
||||
strat := 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++
|
||||
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. Public key is a set
|
||||
// of three x-coordinates: xP,xQ,x(P-Q), where P,Q are points on E_a(Fp2)
|
||||
func PublicKeyGenA(pub3Pt *[3]Fp2, prvBytes []byte) {
|
||||
var xPA, xQA, xRA ProjectivePoint
|
||||
var xPB, xQB, xRB, xR ProjectivePoint
|
||||
var invZP, invZQ, invZR Fp2
|
||||
var tmp ProjectiveCurveParameters
|
||||
var phi isogeny4
|
||||
|
||||
// Load points for A
|
||||
xPA = ProjectivePoint{X: params.A.AffineP, Z: params.OneFp2}
|
||||
xQA = ProjectivePoint{X: params.A.AffineQ, Z: params.OneFp2}
|
||||
xRA = ProjectivePoint{X: params.A.AffineR, Z: params.OneFp2}
|
||||
|
||||
// Load points for B
|
||||
xRB = ProjectivePoint{X: params.B.AffineR, Z: params.OneFp2}
|
||||
xQB = ProjectivePoint{X: params.B.AffineQ, Z: params.OneFp2}
|
||||
xPB = ProjectivePoint{X: params.B.AffineP, Z: params.OneFp2}
|
||||
|
||||
// Find isogeny kernel
|
||||
tmp.C = params.OneFp2
|
||||
xR = ScalarMul3Pt(&tmp, &xPA, &xQA, &xRA, params.A.SecretBitLen, prvBytes)
|
||||
|
||||
// Reset params object and travers isogeny tree
|
||||
tmp.C = params.OneFp2
|
||||
tmp.A = Fp2{}
|
||||
traverseTreePublicKeyA(&tmp, &xR, &xPB, &xQB, &xRB)
|
||||
|
||||
// Secret isogeny
|
||||
phi.GenerateCurve(&xR)
|
||||
xPA = phi.EvaluatePoint(&xPB)
|
||||
xQA = phi.EvaluatePoint(&xQB)
|
||||
xRA = phi.EvaluatePoint(&xRB)
|
||||
Fp2Batch3Inv(&xPA.Z, &xQA.Z, &xRA.Z, &invZP, &invZQ, &invZR)
|
||||
|
||||
mul(&pub3Pt[0], &xPA.X, &invZP)
|
||||
mul(&pub3Pt[1], &xQA.X, &invZQ)
|
||||
mul(&pub3Pt[2], &xRA.X, &invZR)
|
||||
}
|
||||
|
||||
// Generate a public key in the 2-torsion group. Public key is a set
|
||||
// of three x-coordinates: xP,xQ,x(P-Q), where P,Q are points on E_a(Fp2)
|
||||
func PublicKeyGenB(pub3Pt *[3]Fp2, prvBytes []byte) {
|
||||
var xPB, xQB, xRB, xR ProjectivePoint
|
||||
var xPA, xQA, xRA ProjectivePoint
|
||||
var invZP, invZQ, invZR Fp2
|
||||
var tmp ProjectiveCurveParameters
|
||||
var phi isogeny3
|
||||
|
||||
// Load points for B
|
||||
xRB = ProjectivePoint{X: params.B.AffineR, Z: params.OneFp2}
|
||||
xQB = ProjectivePoint{X: params.B.AffineQ, Z: params.OneFp2}
|
||||
xPB = ProjectivePoint{X: params.B.AffineP, Z: params.OneFp2}
|
||||
|
||||
// Load points for A
|
||||
xPA = ProjectivePoint{X: params.A.AffineP, Z: params.OneFp2}
|
||||
xQA = ProjectivePoint{X: params.A.AffineQ, Z: params.OneFp2}
|
||||
xRA = ProjectivePoint{X: params.A.AffineR, Z: params.OneFp2}
|
||||
|
||||
tmp.C = params.OneFp2
|
||||
xR = ScalarMul3Pt(&tmp, &xPB, &xQB, &xRB, params.B.SecretBitLen, prvBytes)
|
||||
|
||||
tmp.C = params.OneFp2
|
||||
tmp.A = Fp2{}
|
||||
traverseTreePublicKeyB(&tmp, &xR, &xPA, &xQA, &xRA)
|
||||
|
||||
phi.GenerateCurve(&xR)
|
||||
xPB = phi.EvaluatePoint(&xPA)
|
||||
xQB = phi.EvaluatePoint(&xQA)
|
||||
xRB = phi.EvaluatePoint(&xRA)
|
||||
Fp2Batch3Inv(&xPB.Z, &xQB.Z, &xRB.Z, &invZP, &invZQ, &invZR)
|
||||
|
||||
mul(&pub3Pt[0], &xPB.X, &invZP)
|
||||
mul(&pub3Pt[1], &xQB.X, &invZQ)
|
||||
mul(&pub3Pt[2], &xRB.X, &invZR)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Key agreement functions
|
||||
//
|
||||
|
||||
// Establishing shared keys in in 2-torsion group
|
||||
func DeriveSecretA(ss, prv []byte, pub3Pt *[3]Fp2) {
|
||||
var cparam ProjectiveCurveParameters
|
||||
var xP, xQ, xQmP ProjectivePoint
|
||||
var xR ProjectivePoint
|
||||
var phi isogeny4
|
||||
var jInv Fp2
|
||||
|
||||
// Recover curve coefficients
|
||||
cparam.C = params.OneFp2
|
||||
RecoverCoordinateA(&cparam, &pub3Pt[0], &pub3Pt[1], &pub3Pt[2])
|
||||
|
||||
// Find kernel of the morphism
|
||||
xP = ProjectivePoint{X: pub3Pt[0], Z: params.OneFp2}
|
||||
xQ = ProjectivePoint{X: pub3Pt[1], Z: params.OneFp2}
|
||||
xQmP = ProjectivePoint{X: pub3Pt[2], Z: params.OneFp2}
|
||||
xR = ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, params.A.SecretBitLen, prv)
|
||||
|
||||
// Traverse isogeny tree
|
||||
traverseTreeSharedKeyA(&cparam, &xR)
|
||||
|
||||
// Calculate j-invariant on isogeneus curve
|
||||
c := phi.GenerateCurve(&xR)
|
||||
RecoverCurveCoefficients4(&cparam, &c)
|
||||
Jinvariant(&cparam, &jInv)
|
||||
FromMontgomery(&jInv, &jInv)
|
||||
Fp2ToBytes(ss, &jInv, params.Bytelen)
|
||||
}
|
||||
|
||||
// Establishing shared keys in in 3-torsion group
|
||||
func DeriveSecretB(ss, prv []byte, pub3Pt *[3]Fp2) {
|
||||
var xP, xQ, xQmP ProjectivePoint
|
||||
var xR ProjectivePoint
|
||||
var cparam ProjectiveCurveParameters
|
||||
var phi isogeny3
|
||||
var jInv Fp2
|
||||
|
||||
// Recover curve coefficients
|
||||
cparam.C = params.OneFp2
|
||||
RecoverCoordinateA(&cparam, &pub3Pt[0], &pub3Pt[1], &pub3Pt[2])
|
||||
|
||||
// Find kernel of the morphism
|
||||
xP = ProjectivePoint{X: pub3Pt[0], Z: params.OneFp2}
|
||||
xQ = ProjectivePoint{X: pub3Pt[1], Z: params.OneFp2}
|
||||
xQmP = ProjectivePoint{X: pub3Pt[2], Z: params.OneFp2}
|
||||
xR = ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, params.B.SecretBitLen, prv)
|
||||
|
||||
// Traverse isogeny tree
|
||||
traverseTreeSharedKeyB(&cparam, &xR)
|
||||
|
||||
// Calculate j-invariant on isogeneus curve
|
||||
c := phi.GenerateCurve(&xR)
|
||||
RecoverCurveCoefficients3(&cparam, &c)
|
||||
Jinvariant(&cparam, &jInv)
|
||||
FromMontgomery(&jInv, &jInv)
|
||||
Fp2ToBytes(ss, &jInv, params.Bytelen)
|
||||
}
|
362
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/curve.go
generated
vendored
Normal file
362
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/curve.go
generated
vendored
Normal file
|
@ -0,0 +1,362 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots.
|
||||
|
||||
package p751
|
||||
|
||||
import (
|
||||
. "github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
)
|
||||
|
||||
// Stores isogeny 3 curve constants
|
||||
type isogeny3 struct {
|
||||
K1 Fp2
|
||||
K2 Fp2
|
||||
}
|
||||
|
||||
// Stores isogeny 4 curve constants
|
||||
type isogeny4 struct {
|
||||
isogeny3
|
||||
K3 Fp2
|
||||
}
|
||||
|
||||
// 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 Jinvariant(cparams *ProjectiveCurveParameters, j *Fp2) {
|
||||
var t0, t1 Fp2
|
||||
|
||||
sqr(j, &cparams.A) // j = A^2
|
||||
sqr(&t1, &cparams.C) // t1 = C^2
|
||||
add(&t0, &t1, &t1) // t0 = t1 + t1
|
||||
sub(&t0, j, &t0) // t0 = j - t0
|
||||
sub(&t0, &t0, &t1) // t0 = t0 - t1
|
||||
sub(j, &t0, &t1) // t0 = t0 - t1
|
||||
sqr(&t1, &t1) // t1 = t1^2
|
||||
mul(j, j, &t1) // j = j * t1
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
sqr(&t1, &t0) // t1 = t0^2
|
||||
mul(&t0, &t0, &t1) // t0 = t0 * t1
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
inv(j, j) // j = 1/j
|
||||
mul(j, &t0, j) // j = t0 * 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 RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2) {
|
||||
var t0, t1 Fp2
|
||||
|
||||
add(&t1, xp, xq) // t1 = Xp + Xq
|
||||
mul(&t0, xp, xq) // t0 = Xp * Xq
|
||||
mul(&curve.A, xr, &t1) // A = X(q-p) * t1
|
||||
add(&curve.A, &curve.A, &t0) // A = A + t0
|
||||
mul(&t0, &t0, xr) // t0 = t0 * X(q-p)
|
||||
sub(&curve.A, &curve.A, ¶ms.OneFp2) // A = A - 1
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
add(&t1, &t1, xr) // t1 = t1 + X(q-p)
|
||||
add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
sqr(&curve.A, &curve.A) // A = A^2
|
||||
inv(&t0, &t0) // t0 = 1/t0
|
||||
mul(&curve.A, &curve.A, &t0) // A = A * t0
|
||||
sub(&curve.A, &curve.A, &t1) // A = A - t1
|
||||
}
|
||||
|
||||
// Computes equivalence (A:C) ~ (A+2C : A-2C)
|
||||
func CalcCurveParamsEquiv3(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
|
||||
var coef CurveCoefficientsEquiv
|
||||
var c2 Fp2
|
||||
|
||||
add(&c2, &cparams.C, &cparams.C)
|
||||
// A24p = A+2*C
|
||||
add(&coef.A, &cparams.A, &c2)
|
||||
// A24m = A-2*C
|
||||
sub(&coef.C, &cparams.A, &c2)
|
||||
return coef
|
||||
}
|
||||
|
||||
// Computes equivalence (A:C) ~ (A+2C : 4C)
|
||||
func CalcCurveParamsEquiv4(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
|
||||
var coefEq CurveCoefficientsEquiv
|
||||
|
||||
add(&coefEq.C, &cparams.C, &cparams.C)
|
||||
// A24p = A+2C
|
||||
add(&coefEq.A, &cparams.A, &coefEq.C)
|
||||
// C24 = 4*C
|
||||
add(&coefEq.C, &coefEq.C, &coefEq.C)
|
||||
return coefEq
|
||||
}
|
||||
|
||||
// Helper function for RightToLeftLadder(). Returns A+2C / 4.
|
||||
func CalcAplus2Over4(cparams *ProjectiveCurveParameters) (ret Fp2) {
|
||||
var tmp Fp2
|
||||
|
||||
// 2C
|
||||
add(&tmp, &cparams.C, &cparams.C)
|
||||
// A+2C
|
||||
add(&ret, &cparams.A, &tmp)
|
||||
// 1/4C
|
||||
add(&tmp, &tmp, &tmp)
|
||||
inv(&tmp, &tmp)
|
||||
// A+2C/4C
|
||||
mul(&ret, &ret, &tmp)
|
||||
return
|
||||
}
|
||||
|
||||
// Recovers (A:C) curve parameters from projectively equivalent (A+2C:A-2C).
|
||||
func RecoverCurveCoefficients3(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
|
||||
add(&cparams.A, &coefEq.A, &coefEq.C)
|
||||
// cparams.A = 2*(A+2C+A-2C) = 4A
|
||||
add(&cparams.A, &cparams.A, &cparams.A)
|
||||
// cparams.C = (A+2C-A+2C) = 4C
|
||||
sub(&cparams.C, &coefEq.A, &coefEq.C)
|
||||
return
|
||||
}
|
||||
|
||||
// Recovers (A:C) curve parameters from projectively equivalent (A+2C:4C).
|
||||
func RecoverCurveCoefficients4(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
|
||||
// cparams.C = (4C)*1/2=2C
|
||||
mul(&cparams.C, &coefEq.C, ¶ms.HalfFp2)
|
||||
// cparams.A = A+2C - 2C = A
|
||||
sub(&cparams.A, &coefEq.A, &cparams.C)
|
||||
// cparams.C = 2C * 1/2 = C
|
||||
mul(&cparams.C, &cparams.C, ¶ms.HalfFp2)
|
||||
}
|
||||
|
||||
// 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 xDbladd(P, Q, QmP *ProjectivePoint, a24 *Fp2) (dblP, PaQ ProjectivePoint) {
|
||||
var t0, t1, t2 Fp2
|
||||
|
||||
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
|
||||
|
||||
add(&t0, xP, zP) // t0 = Xp+Zp
|
||||
sub(&t1, xP, zP) // t1 = Xp-Zp
|
||||
sqr(x2P, &t0) // 2P.X = t0^2
|
||||
sub(&t2, xQ, zQ) // t2 = Xq-Zq
|
||||
add(xPaQ, xQ, zQ) // Xp+q = Xq+Zq
|
||||
mul(&t0, &t0, &t2) // t0 = t0 * t2
|
||||
mul(z2P, &t1, &t1) // 2P.Z = t1 * t1
|
||||
mul(&t1, &t1, xPaQ) // t1 = t1 * Xp+q
|
||||
sub(&t2, x2P, z2P) // t2 = 2P.X - 2P.Z
|
||||
mul(x2P, x2P, z2P) // 2P.X = 2P.X * 2P.Z
|
||||
mul(xPaQ, a24, &t2) // Xp+q = A24 * t2
|
||||
sub(zPaQ, &t0, &t1) // Zp+q = t0 - t1
|
||||
add(z2P, xPaQ, z2P) // 2P.Z = Xp+q + 2P.Z
|
||||
add(xPaQ, &t0, &t1) // Xp+q = t0 + t1
|
||||
mul(z2P, z2P, &t2) // 2P.Z = 2P.Z * t2
|
||||
sqr(zPaQ, zPaQ) // Zp+q = Zp+q ^ 2
|
||||
sqr(xPaQ, xPaQ) // Xp+q = Xp+q ^ 2
|
||||
mul(zPaQ, xQmP, zPaQ) // Zp+q = Xq-p * Zp+q
|
||||
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 Pow2k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
|
||||
var t0, t1 Fp2
|
||||
|
||||
x, z := &xP.X, &xP.Z
|
||||
for i := uint32(0); i < k; i++ {
|
||||
sub(&t0, x, z) // t0 = Xp - Zp
|
||||
add(&t1, x, z) // t1 = Xp + Zp
|
||||
sqr(&t0, &t0) // t0 = t0 ^ 2
|
||||
sqr(&t1, &t1) // t1 = t1 ^ 2
|
||||
mul(z, ¶ms.C, &t0) // Z2p = C24 * t0
|
||||
mul(x, z, &t1) // X2p = Z2p * t1
|
||||
sub(&t1, &t1, &t0) // t1 = t1 - t0
|
||||
mul(&t0, ¶ms.A, &t1) // t0 = A24+ * t1
|
||||
add(z, z, &t0) // Z2p = Z2p + t0
|
||||
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 Pow3k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
|
||||
var t0, t1, t2, t3, t4, t5, t6 Fp2
|
||||
|
||||
x, z := &xP.X, &xP.Z
|
||||
for i := uint32(0); i < k; i++ {
|
||||
sub(&t0, x, z) // t0 = Xp - Zp
|
||||
sqr(&t2, &t0) // t2 = t0^2
|
||||
add(&t1, x, z) // t1 = Xp + Zp
|
||||
sqr(&t3, &t1) // t3 = t1^2
|
||||
add(&t4, &t1, &t0) // t4 = t1 + t0
|
||||
sub(&t0, &t1, &t0) // t0 = t1 - t0
|
||||
sqr(&t1, &t4) // t1 = t4^2
|
||||
sub(&t1, &t1, &t3) // t1 = t1 - t3
|
||||
sub(&t1, &t1, &t2) // t1 = t1 - t2
|
||||
mul(&t5, &t3, ¶ms.A) // t5 = t3 * A24+
|
||||
mul(&t3, &t3, &t5) // t3 = t5 * t3
|
||||
mul(&t6, &t2, ¶ms.C) // t6 = t2 * A24-
|
||||
mul(&t2, &t2, &t6) // t2 = t2 * t6
|
||||
sub(&t3, &t2, &t3) // t3 = t2 - t3
|
||||
sub(&t2, &t5, &t6) // t2 = t5 - t6
|
||||
mul(&t1, &t2, &t1) // t1 = t2 * t1
|
||||
add(&t2, &t3, &t1) // t2 = t3 + t1
|
||||
sqr(&t2, &t2) // t2 = t2^2
|
||||
mul(x, &t2, &t4) // X3p = t2 * t4
|
||||
sub(&t1, &t3, &t1) // t1 = t3 - t1
|
||||
sqr(&t1, &t1) // t1 = t1^2
|
||||
mul(z, &t1, &t0) // Z3p = t1 * t0
|
||||
}
|
||||
}
|
||||
|
||||
// Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3).
|
||||
//
|
||||
// All xi, yi must be distinct.
|
||||
func Fp2Batch3Inv(x1, x2, x3, y1, y2, y3 *Fp2) {
|
||||
var x1x2, t Fp2
|
||||
|
||||
mul(&x1x2, x1, x2) // x1*x2
|
||||
mul(&t, &x1x2, x3) // 1/(x1*x2*x3)
|
||||
inv(&t, &t)
|
||||
mul(y1, &t, x2) // 1/x1
|
||||
mul(y1, y1, x3)
|
||||
mul(y2, &t, x1) // 1/x2
|
||||
mul(y2, y2, x3)
|
||||
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 ScalarMul3Pt(cparams *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint, nbits uint, scalar []uint8) ProjectivePoint {
|
||||
var R0, R2, R1 ProjectivePoint
|
||||
aPlus2Over4 := 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
|
||||
cswap(&R1.X, &R1.Z, &R2.X, &R2.Z, swap)
|
||||
R0, R2 = xDbladd(&R0, &R2, &R1, &aPlus2Over4)
|
||||
}
|
||||
cswap(&R1.X, &R1.Z, &R2.X, &R2.Z, prevBit)
|
||||
return R1
|
||||
}
|
||||
|
||||
// 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 Fp2
|
||||
var coefEq CurveCoefficientsEquiv
|
||||
var K1, K2 = &phi.K1, &phi.K2
|
||||
|
||||
sub(K1, &p.X, &p.Z) // K1 = XP3 - ZP3
|
||||
sqr(&t0, K1) // t0 = K1^2
|
||||
add(K2, &p.X, &p.Z) // K2 = XP3 + ZP3
|
||||
sqr(&t1, K2) // t1 = K2^2
|
||||
add(&t2, &t0, &t1) // t2 = t0 + t1
|
||||
add(&t3, K1, K2) // t3 = K1 + K2
|
||||
sqr(&t3, &t3) // t3 = t3^2
|
||||
sub(&t3, &t3, &t2) // t3 = t3 - t2
|
||||
add(&t2, &t1, &t3) // t2 = t1 + t3
|
||||
add(&t3, &t3, &t0) // t3 = t3 + t0
|
||||
add(&t4, &t3, &t0) // t4 = t3 + t0
|
||||
add(&t4, &t4, &t4) // t4 = t4 + t4
|
||||
add(&t4, &t1, &t4) // t4 = t1 + t4
|
||||
mul(&coefEq.C, &t2, &t4) // A24m = t2 * t4
|
||||
add(&t4, &t1, &t2) // t4 = t1 + t2
|
||||
add(&t4, &t4, &t4) // t4 = t4 + t4
|
||||
add(&t4, &t0, &t4) // t4 = t0 + t4
|
||||
mul(&t4, &t3, &t4) // t4 = t3 * t4
|
||||
sub(&t0, &t4, &coefEq.C) // t0 = t4 - A24m
|
||||
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 Fp2
|
||||
var q ProjectivePoint
|
||||
var K1, K2 = &phi.K1, &phi.K2
|
||||
var px, pz = &p.X, &p.Z
|
||||
|
||||
add(&t0, px, pz) // t0 = XQ + ZQ
|
||||
sub(&t1, px, pz) // t1 = XQ - ZQ
|
||||
mul(&t0, K1, &t0) // t2 = K1 * t0
|
||||
mul(&t1, K2, &t1) // t1 = K2 * t1
|
||||
add(&t2, &t0, &t1) // t2 = t0 + t1
|
||||
sub(&t0, &t1, &t0) // t0 = t1 - t0
|
||||
sqr(&t2, &t2) // t2 = t2 ^ 2
|
||||
sqr(&t0, &t0) // t0 = t0 ^ 2
|
||||
mul(&q.X, px, &t2) // XQ'= XQ * t2
|
||||
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
|
||||
|
||||
sub(K2, xp4, zp4)
|
||||
add(K3, xp4, zp4)
|
||||
sqr(K1, zp4)
|
||||
add(K1, K1, K1)
|
||||
sqr(&coefEq.C, K1)
|
||||
add(K1, K1, K1)
|
||||
sqr(&coefEq.A, xp4)
|
||||
add(&coefEq.A, &coefEq.A, &coefEq.A)
|
||||
sqr(&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 Fp2
|
||||
var q = *p
|
||||
var xq, zq = &q.X, &q.Z
|
||||
var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
|
||||
|
||||
add(&t0, xq, zq)
|
||||
sub(&t1, xq, zq)
|
||||
mul(xq, &t0, K2)
|
||||
mul(zq, &t1, K3)
|
||||
mul(&t0, &t0, &t1)
|
||||
mul(&t0, &t0, K1)
|
||||
add(&t1, xq, zq)
|
||||
sub(zq, xq, zq)
|
||||
sqr(&t1, &t1)
|
||||
sqr(zq, zq)
|
||||
add(xq, &t0, &t1)
|
||||
sub(&t0, zq, &t0)
|
||||
mul(xq, xq, &t1)
|
||||
mul(zq, zq, &t0)
|
||||
return q
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
// Package p751 provides implementation of field arithmetic used in SIDH and SIKE.
|
||||
package p751
|
|
@ -0,0 +1,195 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots.
|
||||
|
||||
package p751
|
||||
|
||||
import (
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
)
|
||||
|
||||
// Montgomery multiplication. Input values must be already
|
||||
// in Montgomery domain.
|
||||
func mulP(dest, lhs, rhs *common.Fp) {
|
||||
var ab common.FpX2
|
||||
mulP751(&ab, lhs, rhs) // = a*b*R*R
|
||||
rdcP751(dest, &ab) // = a*b*R mod p
|
||||
}
|
||||
|
||||
// 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.
|
||||
// All values in Montgomery domains
|
||||
// Set dest = x^(2^k), for k >= 1, by repeated squarings.
|
||||
func p34(dest, x *common.Fp) {
|
||||
var lookup [16]common.Fp
|
||||
|
||||
// This performs sum(powStrategy) + 1 squarings and len(lookup) + len(mulStrategy)
|
||||
// multiplications.
|
||||
powStrategy := []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 := []uint8{15, 11, 10, 0, 15, 3, 3, 3, 4, 4, 9, 7, 11, 11, 5, 3, 12, 2, 10, 8, 5, 2, 8, 3, 5, 4, 11, 4, 0, 9, 2, 1, 12, 7, 5, 14, 15, 0, 14, 5, 6, 4, 5, 13, 6, 9, 7, 15, 1, 14, 11, 15, 12, 5, 0, 10, 9, 7, 7, 10, 14, 6, 11, 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, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1}
|
||||
initialMul := uint8(13)
|
||||
|
||||
// Precompute lookup table of odd multiples of x for window
|
||||
// size k=5.
|
||||
var xx common.Fp
|
||||
mulP(&xx, x, x)
|
||||
lookup[0] = *x
|
||||
for i := 1; i < 16; i++ {
|
||||
mulP(&lookup[i], &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]
|
||||
for i := uint8(0); i < uint8(len(powStrategy)); i++ {
|
||||
mulP(dest, dest, dest)
|
||||
for j := uint8(1); j < powStrategy[i]; j++ {
|
||||
mulP(dest, dest, dest)
|
||||
}
|
||||
mulP(dest, dest, &lookup[mulStrategy[i]])
|
||||
}
|
||||
}
|
||||
|
||||
func add(dest, lhs, rhs *common.Fp2) {
|
||||
addP751(&dest.A, &lhs.A, &rhs.A)
|
||||
addP751(&dest.B, &lhs.B, &rhs.B)
|
||||
}
|
||||
|
||||
func sub(dest, lhs, rhs *common.Fp2) {
|
||||
subP751(&dest.A, &lhs.A, &rhs.A)
|
||||
subP751(&dest.B, &lhs.B, &rhs.B)
|
||||
}
|
||||
|
||||
func mul(dest, lhs, rhs *common.Fp2) {
|
||||
var bMinA, cMinD common.Fp
|
||||
var ac, bd common.FpX2
|
||||
var adPlusBc common.FpX2
|
||||
var acMinBd common.FpX2
|
||||
|
||||
// Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b).
|
||||
//
|
||||
// (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.
|
||||
mulP751(&ac, &lhs.A, &rhs.A) // = a*c*R*R
|
||||
mulP751(&bd, &lhs.B, &rhs.B) // = b*d*R*R
|
||||
subP751(&bMinA, &lhs.B, &lhs.A) // = (b-a)*R
|
||||
subP751(&cMinD, &rhs.A, &rhs.B) // = (c-d)*R
|
||||
mulP751(&adPlusBc, &bMinA, &cMinD) // = (b-a)*(c-d)*R*R
|
||||
adlP751(&adPlusBc, &adPlusBc, &ac) // = ((b-a)*(c-d) + a*c)*R*R
|
||||
adlP751(&adPlusBc, &adPlusBc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R
|
||||
rdcP751(&dest.B, &adPlusBc) // = (a*d + b*c)*R mod p
|
||||
sulP751(&acMinBd, &ac, &bd) // = (a*c - b*d)*R*R
|
||||
rdcP751(&dest.A, &acMinBd) // = (a*c - b*d)*R mod p
|
||||
}
|
||||
|
||||
// Set dest = 1/x
|
||||
//
|
||||
// Allowed to overlap dest with x.
|
||||
//
|
||||
// Returns dest to allow chaining operations.
|
||||
func inv(dest, x *common.Fp2) {
|
||||
var e1, e2 common.FpX2
|
||||
var f1, f2 common.Fp
|
||||
|
||||
// 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.
|
||||
|
||||
mulP751(&e1, &x.A, &x.A) // = a*a*R*R
|
||||
mulP751(&e2, &x.B, &x.B) // = b*b*R*R
|
||||
adlP751(&e1, &e1, &e2) // = (a^2 + b^2)*R*R
|
||||
rdcP751(&f1, &e1) // = (a^2 + b^2)*R mod p
|
||||
// Now f1 = a^2 + b^2
|
||||
|
||||
mulP(&f2, &f1, &f1)
|
||||
p34(&f2, &f2)
|
||||
mulP(&f2, &f2, &f2)
|
||||
mulP(&f2, &f2, &f1)
|
||||
|
||||
mulP751(&e1, &x.A, &f2)
|
||||
rdcP751(&dest.A, &e1)
|
||||
|
||||
subP751(&f1, &common.Fp{}, &x.B)
|
||||
mulP751(&e1, &f1, &f2)
|
||||
rdcP751(&dest.B, &e1)
|
||||
}
|
||||
|
||||
func sqr(dest, x *common.Fp2) {
|
||||
var a2, aPlusB, aMinusB common.Fp
|
||||
var a2MinB2, ab2 common.FpX2
|
||||
|
||||
a := &x.A
|
||||
b := &x.B
|
||||
|
||||
// (a + bi)*(a + bi) = (a^2 - b^2) + 2abi.
|
||||
addP751(&a2, a, a) // = a*R + a*R = 2*a*R
|
||||
addP751(&aPlusB, a, b) // = a*R + b*R = (a+b)*R
|
||||
subP751(&aMinusB, a, b) // = a*R - b*R = (a-b)*R
|
||||
mulP751(&a2MinB2, &aPlusB, &aMinusB) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R
|
||||
mulP751(&ab2, &a2, b) // = 2*a*b*R*R
|
||||
rdcP751(&dest.A, &a2MinB2) // = (a^2 - b^2)*R mod p
|
||||
rdcP751(&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 cswap(xPx, xPz, xQx, xQz *common.Fp2, choice uint8) {
|
||||
cswapP751(&xPx.A, &xQx.A, choice)
|
||||
cswapP751(&xPx.B, &xQx.B, choice)
|
||||
cswapP751(&xPz.A, &xQz.A, choice)
|
||||
cswapP751(&xPz.B, &xQz.B, choice)
|
||||
}
|
||||
|
||||
// Converts in.A and in.B to Montgomery domain and stores
|
||||
// in 'out'
|
||||
// out.A = in.A * R mod p
|
||||
// out.B = in.B * R mod p
|
||||
// Performs v = v*R^2*R^(-1) mod p, for both in.A and in.B
|
||||
func ToMontgomery(out, in *common.Fp2) {
|
||||
var aRR common.FpX2
|
||||
|
||||
// a*R*R
|
||||
mulP751(&aRR, &in.A, &P751R2)
|
||||
// a*R mod p
|
||||
rdcP751(&out.A, &aRR)
|
||||
mulP751(&aRR, &in.B, &P751R2)
|
||||
rdcP751(&out.B, &aRR)
|
||||
}
|
||||
|
||||
// Converts in.A and in.B from Montgomery domain and stores
|
||||
// in 'out'
|
||||
// out.A = in.A mod p
|
||||
// out.B = in.B mod p
|
||||
//
|
||||
// After returning from the call 'in' is not modified.
|
||||
func FromMontgomery(out, in *common.Fp2) {
|
||||
var aR common.FpX2
|
||||
|
||||
// convert from montgomery domain
|
||||
copy(aR[:], in.A[:])
|
||||
rdcP751(&out.A, &aR) // = a mod p in [0, 2p)
|
||||
modP751(&out.A) // = a mod p in [0, p)
|
||||
for i := range aR {
|
||||
aR[i] = 0
|
||||
}
|
||||
copy(aR[:], in.B[:])
|
||||
rdcP751(&out.B, &aR)
|
||||
modP751(&out.B)
|
||||
}
|
235
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/params.go
generated
vendored
Normal file
235
vendor/github.com/cloudflare/circl/dh/sidh/internal/p751/params.go
generated
vendored
Normal file
|
@ -0,0 +1,235 @@
|
|||
package p751
|
||||
|
||||
//go:generate go run ../templates/gen.go P751
|
||||
|
||||
import (
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
const (
|
||||
// Number of uint64 limbs used to store field element
|
||||
FpWords = 12
|
||||
)
|
||||
|
||||
var (
|
||||
// HasBMI2 signals support for MULX which is in BMI2
|
||||
HasBMI2 = cpu.X86.HasBMI2
|
||||
// HasADXandBMI2 signals support for ADX and BMI2
|
||||
HasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX
|
||||
// P751 is a prime used by field Fp751
|
||||
P751 = common.Fp{
|
||||
0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
|
||||
0xffffffffffffffff, 0xffffffffffffffff, 0xeeafffffffffffff,
|
||||
0xe3ec968549f878a8, 0xda959b1a13f7cc76, 0x084e9867d6ebe876,
|
||||
0x8562b5045cb25748, 0x0e12909f97badc66, 0x00006fe5d541f71c}
|
||||
|
||||
// P751x2 = 2*p751 - 1
|
||||
P751x2 = common.Fp{
|
||||
0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xDD5FFFFFFFFFFFFF,
|
||||
0xC7D92D0A93F0F151, 0xB52B363427EF98ED, 0x109D30CFADD7D0ED,
|
||||
0x0AC56A08B964AE90, 0x1C25213F2F75B8CD, 0x0000DFCBAA83EE38}
|
||||
|
||||
// P751p1 = p751 + 1
|
||||
P751p1 = common.Fp{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0xeeb0000000000000,
|
||||
0xe3ec968549f878a8, 0xda959b1a13f7cc76, 0x084e9867d6ebe876,
|
||||
0x8562b5045cb25748, 0x0e12909f97badc66, 0x00006fe5d541f71c}
|
||||
|
||||
// P751R2 = (2^768)^2 mod p
|
||||
P751R2 = common.Fp{
|
||||
2535603850726686808, 15780896088201250090, 6788776303855402382,
|
||||
17585428585582356230, 5274503137951975249, 2266259624764636289,
|
||||
11695651972693921304, 13072885652150159301, 4908312795585420432,
|
||||
6229583484603254826, 488927695601805643, 72213483953973}
|
||||
|
||||
// P751p1Zeros number of 0 digits in the least significant part of P751+1
|
||||
P751p1Zeros = 5
|
||||
|
||||
params common.SidhParams
|
||||
)
|
||||
|
||||
func init() {
|
||||
params = common.SidhParams{
|
||||
ID: common.Fp751,
|
||||
// SIDH public key byte size.
|
||||
PublicKeySize: 564,
|
||||
// SIDH shared secret byte size.
|
||||
SharedSecretSize: 188,
|
||||
A: common.DomainParams{
|
||||
// The x-coordinate of PA
|
||||
AffineP: common.Fp2{
|
||||
A: common.Fp{
|
||||
0xC2FC08CEAB50AD8B, 0x1D7D710F55E457B1, 0xE8738D92953DCD6E,
|
||||
0xBAA7EBEE8A3418AA, 0xC9A288345F03F46F, 0xC8D18D167CFE2616,
|
||||
0x02043761F6B1C045, 0xAA1975E13180E7E9, 0x9E13D3FDC6690DE6,
|
||||
0x3A024640A3A3BB4F, 0x4E5AD44E6ACBBDAE, 0x0000544BEB561DAD,
|
||||
},
|
||||
B: common.Fp{
|
||||
0xE6CC41D21582E411, 0x07C2ECB7C5DF400A, 0xE8E34B521432AEC4,
|
||||
0x50761E2AB085167D, 0x032CFBCAA6094B3C, 0x6C522F5FDF9DDD71,
|
||||
0x1319217DC3A1887D, 0xDC4FB25803353A86, 0x362C8D7B63A6AB09,
|
||||
0x39DCDFBCE47EA488, 0x4C27C99A2C28D409, 0x00003CB0075527C4,
|
||||
},
|
||||
},
|
||||
// The x-coordinate of QA
|
||||
AffineQ: common.Fp2{
|
||||
A: common.Fp{
|
||||
0xD56FE52627914862, 0x1FAD60DC96B5BAEA, 0x01E137D0BF07AB91,
|
||||
0x404D3E9252161964, 0x3C5385E4CD09A337, 0x4476426769E4AF73,
|
||||
0x9790C6DB989DFE33, 0xE06E1C04D2AA8B5E, 0x38C08185EDEA73B9,
|
||||
0xAA41F678A4396CA6, 0x92B9259B2229E9A0, 0x00002F9326818BE0,
|
||||
},
|
||||
B: common.Fp{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
},
|
||||
},
|
||||
// The x-coordinate of RA = PA-QA
|
||||
AffineR: common.Fp2{
|
||||
A: common.Fp{
|
||||
0x0BB84441DFFD19B3, 0x84B4DEA99B48C18E, 0x692DE648AD313805,
|
||||
0xE6D72761B6DFAEE0, 0x223975C672C3058D, 0xA0FDE0C3CBA26FDC,
|
||||
0xA5326132A922A3CA, 0xCA5E7F5D5EA96FA4, 0x127C7EFE33FFA8C6,
|
||||
0x4749B1567E2A23C4, 0x2B7DF5B4AF413BFA, 0x0000656595B9623C,
|
||||
},
|
||||
B: common.Fp{
|
||||
0xED78C17F1EC71BE8, 0xF824D6DF753859B1, 0x33A10839B2A8529F,
|
||||
0xFC03E9E25FDEA796, 0xC4708A8054DF1762, 0x4034F2EC034C6467,
|
||||
0xABFB70FBF06ECC79, 0xDABE96636EC108B7, 0x49CBCFB090605FD3,
|
||||
0x20B89711819A45A7, 0xFB8E1590B2B0F63E, 0x0000556A5F964AB2,
|
||||
},
|
||||
},
|
||||
// Max size of secret key for 2-torsion group, corresponds to 2^e2 - 1
|
||||
SecretBitLen: 372,
|
||||
// SecretBitLen in bytes.
|
||||
SecretByteLen: 47,
|
||||
// 2-torsion group computation strategy
|
||||
IsogenyStrategy: []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},
|
||||
},
|
||||
B: common.DomainParams{
|
||||
// The x-coordinate of PB
|
||||
AffineP: common.Fp2{
|
||||
A: common.Fp{
|
||||
0xCFB6D71EF867AB0B, 0x4A5FDD76E9A45C76, 0x38B1EE69194B1F03,
|
||||
0xF6E7B18A7761F3F0, 0xFCF01A486A52C84C, 0xCBE2F63F5AA75466,
|
||||
0x6487BCE837B5E4D6, 0x7747F5A8C622E9B8, 0x4CBFE1E4EE6AEBBA,
|
||||
0x8A8616A13FA91512, 0x53DB980E1579E0A5, 0x000058FEBFF3BE69,
|
||||
},
|
||||
B: common.Fp{
|
||||
0xA492034E7C075CC3, 0x677BAF00B04AA430, 0x3AAE0C9A755C94C8,
|
||||
0x1DC4B064E9EBB08B, 0x3684EDD04E826C66, 0x9BAA6CB661F01B22,
|
||||
0x20285A00AD2EFE35, 0xDCE95ABD0497065F, 0x16C7FBB3778E3794,
|
||||
0x26B3AC29CEF25AAF, 0xFB3C28A31A30AC1D, 0x000046ED190624EE,
|
||||
},
|
||||
},
|
||||
// The x-coordinate of QB
|
||||
AffineQ: common.Fp2{
|
||||
A: common.Fp{
|
||||
0xF1A8C9ED7B96C4AB, 0x299429DA5178486E, 0xEF4926F20CD5C2F4,
|
||||
0x683B2E2858B4716A, 0xDDA2FBCC3CAC3EEB, 0xEC055F9F3A600460,
|
||||
0xD5A5A17A58C3848B, 0x4652D836F42EAED5, 0x2F2E71ED78B3A3B3,
|
||||
0xA771C057180ADD1D, 0xC780A5D2D835F512, 0x0000114EA3B55AC1,
|
||||
},
|
||||
B: common.Fp{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
},
|
||||
},
|
||||
// The x-coordinate of RB = PB - QB
|
||||
AffineR: common.Fp2{
|
||||
A: common.Fp{
|
||||
0x1C0D6733769D0F31, 0xF084C3086E2659D1, 0xE23D5DA27BCBD133,
|
||||
0xF38EC9A8D5864025, 0x6426DC781B3B645B, 0x4B24E8E3C9FB03EE,
|
||||
0x6432792F9D2CEA30, 0x7CC8E8B1AE76E857, 0x7F32BFB626BB8963,
|
||||
0xB9F05995B48D7B74, 0x4D71200A7D67E042, 0x0000228457AF0637,
|
||||
},
|
||||
B: common.Fp{
|
||||
0x4AE37E7D8F72BD95, 0xDD2D504B3E993488, 0x5D14E7FA1ECB3C3E,
|
||||
0x127610CEB75D6350, 0x255B4B4CAC446B11, 0x9EA12336C1F70CAF,
|
||||
0x79FA68A2147BC2F8, 0x11E895CFDADBBC49, 0xE4B9D3C4D6356C18,
|
||||
0x44B25856A67F951C, 0x5851541F61308D0B, 0x00002FFD994F7E4C,
|
||||
},
|
||||
},
|
||||
// Size of secret key for 3-torsion group, corresponds to log_2(3^e3) - 1.
|
||||
SecretBitLen: 378,
|
||||
// SecretBitLen in bytes.
|
||||
SecretByteLen: 48,
|
||||
// 3-torsion group computation strategy
|
||||
IsogenyStrategy: []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},
|
||||
},
|
||||
// 1*R mod p
|
||||
OneFp2: common.Fp2{
|
||||
A: common.Fp{
|
||||
0x00000000000249ad, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x8310000000000000,
|
||||
0x5527b1e4375c6c66, 0x697797bf3f4f24d0, 0xc89db7b2ac5c4e2e,
|
||||
0x4ca4b439d2076956, 0x10f7926c7512c7e9, 0x00002d5b24bce5e2},
|
||||
},
|
||||
// 1/2 * R mod p
|
||||
HalfFp2: common.Fp2{
|
||||
A: common.Fp{
|
||||
0x00000000000124D6, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0xB8E0000000000000,
|
||||
0x9C8A2434C0AA7287, 0xA206996CA9A378A3, 0x6876280D41A41B52,
|
||||
0xE903B49F175CE04F, 0x0F8511860666D227, 0x00004EA07CFF6E7F},
|
||||
},
|
||||
MsgLen: 32,
|
||||
// SIKEp751 provides 128 bit of classical security ([SIKE], 5.1)
|
||||
KemSize: 24,
|
||||
// ceil(751+7/8)
|
||||
Bytelen: 94,
|
||||
CiphertextSize: 24 + 8 + 564,
|
||||
}
|
||||
|
||||
common.Register(common.Fp751, ¶ms)
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2009 The Go Authors. 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 Google Inc. 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.
|
|
@ -0,0 +1,7 @@
|
|||
// Package shake provides implementation of SHA-3 and cSHAKE
|
||||
// This code has been copied from golang.org/x/crypto/sha3
|
||||
// and havily modified. This version doesn't use heap when
|
||||
// computing cSHAKE. It makes it possible to allocate
|
||||
// heap once when object is created and then reuse heap
|
||||
// allocated structures in subsequent calls.
|
||||
package shake
|
412
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/keccakf.go
generated
vendored
Normal file
412
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/keccakf.go
generated
vendored
Normal file
|
@ -0,0 +1,412 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !amd64 appengine gccgo
|
||||
|
||||
package shake
|
||||
|
||||
// rc stores the round constants for use in the ι step.
|
||||
var rc = [24]uint64{
|
||||
0x0000000000000001,
|
||||
0x0000000000008082,
|
||||
0x800000000000808A,
|
||||
0x8000000080008000,
|
||||
0x000000000000808B,
|
||||
0x0000000080000001,
|
||||
0x8000000080008081,
|
||||
0x8000000000008009,
|
||||
0x000000000000008A,
|
||||
0x0000000000000088,
|
||||
0x0000000080008009,
|
||||
0x000000008000000A,
|
||||
0x000000008000808B,
|
||||
0x800000000000008B,
|
||||
0x8000000000008089,
|
||||
0x8000000000008003,
|
||||
0x8000000000008002,
|
||||
0x8000000000000080,
|
||||
0x000000000000800A,
|
||||
0x800000008000000A,
|
||||
0x8000000080008081,
|
||||
0x8000000000008080,
|
||||
0x0000000080000001,
|
||||
0x8000000080008008,
|
||||
}
|
||||
|
||||
// keccakF1600 applies the Keccak permutation to a 1600b-wide
|
||||
// state represented as a slice of 25 uint64s.
|
||||
func keccakF1600(a *[25]uint64) {
|
||||
// Implementation translated from Keccak-inplace.c
|
||||
// in the keccak reference code.
|
||||
var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64
|
||||
|
||||
for i := 0; i < 24; i += 4 {
|
||||
// Combines the 5 steps in each round into 2 steps.
|
||||
// Unrolls 4 rounds per loop and spreads some steps across rounds.
|
||||
|
||||
// Round 1
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[6] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[12] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[18] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[24] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i]
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[16] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[22] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[3] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[1] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[7] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[19] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[11] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[23] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[4] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[2] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[8] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[14] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 2
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[16] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[7] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[23] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[14] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1]
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[11] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[2] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[18] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[6] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[22] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[4] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[1] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[8] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[24] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[12] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[3] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[19] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 3
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[11] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[22] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[8] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[19] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2]
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[1] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[12] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[23] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[16] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[2] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[24] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[6] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[3] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[14] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[7] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[18] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[4] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 4
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[1] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[2] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[3] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[4] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3]
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[6] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[7] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[8] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[11] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[12] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[14] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[16] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[18] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[19] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[22] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[23] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[24] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
}
|
||||
}
|
13
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/keccakf_amd64.go
generated
vendored
Normal file
13
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/keccakf_amd64.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
package shake
|
||||
|
||||
// This function is implemented in keccakf_amd64.s.
|
||||
|
||||
//go:noescape
|
||||
|
||||
func keccakF1600(a *[25]uint64)
|
390
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/keccakf_amd64.s
generated
vendored
Normal file
390
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/keccakf_amd64.s
generated
vendored
Normal file
|
@ -0,0 +1,390 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!appengine,!gccgo
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources at https://github.com/gvanas/KeccakCodePackage
|
||||
|
||||
// Offsets in state
|
||||
#define _ba (0*8)
|
||||
#define _be (1*8)
|
||||
#define _bi (2*8)
|
||||
#define _bo (3*8)
|
||||
#define _bu (4*8)
|
||||
#define _ga (5*8)
|
||||
#define _ge (6*8)
|
||||
#define _gi (7*8)
|
||||
#define _go (8*8)
|
||||
#define _gu (9*8)
|
||||
#define _ka (10*8)
|
||||
#define _ke (11*8)
|
||||
#define _ki (12*8)
|
||||
#define _ko (13*8)
|
||||
#define _ku (14*8)
|
||||
#define _ma (15*8)
|
||||
#define _me (16*8)
|
||||
#define _mi (17*8)
|
||||
#define _mo (18*8)
|
||||
#define _mu (19*8)
|
||||
#define _sa (20*8)
|
||||
#define _se (21*8)
|
||||
#define _si (22*8)
|
||||
#define _so (23*8)
|
||||
#define _su (24*8)
|
||||
|
||||
// Temporary registers
|
||||
#define rT1 AX
|
||||
|
||||
// Round vars
|
||||
#define rpState DI
|
||||
#define rpStack SP
|
||||
|
||||
#define rDa BX
|
||||
#define rDe CX
|
||||
#define rDi DX
|
||||
#define rDo R8
|
||||
#define rDu R9
|
||||
|
||||
#define rBa R10
|
||||
#define rBe R11
|
||||
#define rBi R12
|
||||
#define rBo R13
|
||||
#define rBu R14
|
||||
|
||||
#define rCa SI
|
||||
#define rCe BP
|
||||
#define rCi rBi
|
||||
#define rCo rBo
|
||||
#define rCu R15
|
||||
|
||||
#define MOVQ_RBI_RCE MOVQ rBi, rCe
|
||||
#define XORQ_RT1_RCA XORQ rT1, rCa
|
||||
#define XORQ_RT1_RCE XORQ rT1, rCe
|
||||
#define XORQ_RBA_RCU XORQ rBa, rCu
|
||||
#define XORQ_RBE_RCU XORQ rBe, rCu
|
||||
#define XORQ_RDU_RCU XORQ rDu, rCu
|
||||
#define XORQ_RDA_RCA XORQ rDa, rCa
|
||||
#define XORQ_RDE_RCE XORQ rDe, rCe
|
||||
|
||||
#define mKeccakRound(iState, oState, rc, B_RBI_RCE, G_RT1_RCA, G_RT1_RCE, G_RBA_RCU, K_RT1_RCA, K_RT1_RCE, K_RBA_RCU, M_RT1_RCA, M_RT1_RCE, M_RBE_RCU, S_RDU_RCU, S_RDA_RCA, S_RDE_RCE) \
|
||||
/* Prepare round */ \
|
||||
MOVQ rCe, rDa; \
|
||||
ROLQ $1, rDa; \
|
||||
\
|
||||
MOVQ _bi(iState), rCi; \
|
||||
XORQ _gi(iState), rDi; \
|
||||
XORQ rCu, rDa; \
|
||||
XORQ _ki(iState), rCi; \
|
||||
XORQ _mi(iState), rDi; \
|
||||
XORQ rDi, rCi; \
|
||||
\
|
||||
MOVQ rCi, rDe; \
|
||||
ROLQ $1, rDe; \
|
||||
\
|
||||
MOVQ _bo(iState), rCo; \
|
||||
XORQ _go(iState), rDo; \
|
||||
XORQ rCa, rDe; \
|
||||
XORQ _ko(iState), rCo; \
|
||||
XORQ _mo(iState), rDo; \
|
||||
XORQ rDo, rCo; \
|
||||
\
|
||||
MOVQ rCo, rDi; \
|
||||
ROLQ $1, rDi; \
|
||||
\
|
||||
MOVQ rCu, rDo; \
|
||||
XORQ rCe, rDi; \
|
||||
ROLQ $1, rDo; \
|
||||
\
|
||||
MOVQ rCa, rDu; \
|
||||
XORQ rCi, rDo; \
|
||||
ROLQ $1, rDu; \
|
||||
\
|
||||
/* Result b */ \
|
||||
MOVQ _ba(iState), rBa; \
|
||||
MOVQ _ge(iState), rBe; \
|
||||
XORQ rCo, rDu; \
|
||||
MOVQ _ki(iState), rBi; \
|
||||
MOVQ _mo(iState), rBo; \
|
||||
MOVQ _su(iState), rBu; \
|
||||
XORQ rDe, rBe; \
|
||||
ROLQ $44, rBe; \
|
||||
XORQ rDi, rBi; \
|
||||
XORQ rDa, rBa; \
|
||||
ROLQ $43, rBi; \
|
||||
\
|
||||
MOVQ rBe, rCa; \
|
||||
MOVQ rc, rT1; \
|
||||
ORQ rBi, rCa; \
|
||||
XORQ rBa, rT1; \
|
||||
XORQ rT1, rCa; \
|
||||
MOVQ rCa, _ba(oState); \
|
||||
\
|
||||
XORQ rDu, rBu; \
|
||||
ROLQ $14, rBu; \
|
||||
MOVQ rBa, rCu; \
|
||||
ANDQ rBe, rCu; \
|
||||
XORQ rBu, rCu; \
|
||||
MOVQ rCu, _bu(oState); \
|
||||
\
|
||||
XORQ rDo, rBo; \
|
||||
ROLQ $21, rBo; \
|
||||
MOVQ rBo, rT1; \
|
||||
ANDQ rBu, rT1; \
|
||||
XORQ rBi, rT1; \
|
||||
MOVQ rT1, _bi(oState); \
|
||||
\
|
||||
NOTQ rBi; \
|
||||
ORQ rBa, rBu; \
|
||||
ORQ rBo, rBi; \
|
||||
XORQ rBo, rBu; \
|
||||
XORQ rBe, rBi; \
|
||||
MOVQ rBu, _bo(oState); \
|
||||
MOVQ rBi, _be(oState); \
|
||||
B_RBI_RCE; \
|
||||
\
|
||||
/* Result g */ \
|
||||
MOVQ _gu(iState), rBe; \
|
||||
XORQ rDu, rBe; \
|
||||
MOVQ _ka(iState), rBi; \
|
||||
ROLQ $20, rBe; \
|
||||
XORQ rDa, rBi; \
|
||||
ROLQ $3, rBi; \
|
||||
MOVQ _bo(iState), rBa; \
|
||||
MOVQ rBe, rT1; \
|
||||
ORQ rBi, rT1; \
|
||||
XORQ rDo, rBa; \
|
||||
MOVQ _me(iState), rBo; \
|
||||
MOVQ _si(iState), rBu; \
|
||||
ROLQ $28, rBa; \
|
||||
XORQ rBa, rT1; \
|
||||
MOVQ rT1, _ga(oState); \
|
||||
G_RT1_RCA; \
|
||||
\
|
||||
XORQ rDe, rBo; \
|
||||
ROLQ $45, rBo; \
|
||||
MOVQ rBi, rT1; \
|
||||
ANDQ rBo, rT1; \
|
||||
XORQ rBe, rT1; \
|
||||
MOVQ rT1, _ge(oState); \
|
||||
G_RT1_RCE; \
|
||||
\
|
||||
XORQ rDi, rBu; \
|
||||
ROLQ $61, rBu; \
|
||||
MOVQ rBu, rT1; \
|
||||
ORQ rBa, rT1; \
|
||||
XORQ rBo, rT1; \
|
||||
MOVQ rT1, _go(oState); \
|
||||
\
|
||||
ANDQ rBe, rBa; \
|
||||
XORQ rBu, rBa; \
|
||||
MOVQ rBa, _gu(oState); \
|
||||
NOTQ rBu; \
|
||||
G_RBA_RCU; \
|
||||
\
|
||||
ORQ rBu, rBo; \
|
||||
XORQ rBi, rBo; \
|
||||
MOVQ rBo, _gi(oState); \
|
||||
\
|
||||
/* Result k */ \
|
||||
MOVQ _be(iState), rBa; \
|
||||
MOVQ _gi(iState), rBe; \
|
||||
MOVQ _ko(iState), rBi; \
|
||||
MOVQ _mu(iState), rBo; \
|
||||
MOVQ _sa(iState), rBu; \
|
||||
XORQ rDi, rBe; \
|
||||
ROLQ $6, rBe; \
|
||||
XORQ rDo, rBi; \
|
||||
ROLQ $25, rBi; \
|
||||
MOVQ rBe, rT1; \
|
||||
ORQ rBi, rT1; \
|
||||
XORQ rDe, rBa; \
|
||||
ROLQ $1, rBa; \
|
||||
XORQ rBa, rT1; \
|
||||
MOVQ rT1, _ka(oState); \
|
||||
K_RT1_RCA; \
|
||||
\
|
||||
XORQ rDu, rBo; \
|
||||
ROLQ $8, rBo; \
|
||||
MOVQ rBi, rT1; \
|
||||
ANDQ rBo, rT1; \
|
||||
XORQ rBe, rT1; \
|
||||
MOVQ rT1, _ke(oState); \
|
||||
K_RT1_RCE; \
|
||||
\
|
||||
XORQ rDa, rBu; \
|
||||
ROLQ $18, rBu; \
|
||||
NOTQ rBo; \
|
||||
MOVQ rBo, rT1; \
|
||||
ANDQ rBu, rT1; \
|
||||
XORQ rBi, rT1; \
|
||||
MOVQ rT1, _ki(oState); \
|
||||
\
|
||||
MOVQ rBu, rT1; \
|
||||
ORQ rBa, rT1; \
|
||||
XORQ rBo, rT1; \
|
||||
MOVQ rT1, _ko(oState); \
|
||||
\
|
||||
ANDQ rBe, rBa; \
|
||||
XORQ rBu, rBa; \
|
||||
MOVQ rBa, _ku(oState); \
|
||||
K_RBA_RCU; \
|
||||
\
|
||||
/* Result m */ \
|
||||
MOVQ _ga(iState), rBe; \
|
||||
XORQ rDa, rBe; \
|
||||
MOVQ _ke(iState), rBi; \
|
||||
ROLQ $36, rBe; \
|
||||
XORQ rDe, rBi; \
|
||||
MOVQ _bu(iState), rBa; \
|
||||
ROLQ $10, rBi; \
|
||||
MOVQ rBe, rT1; \
|
||||
MOVQ _mi(iState), rBo; \
|
||||
ANDQ rBi, rT1; \
|
||||
XORQ rDu, rBa; \
|
||||
MOVQ _so(iState), rBu; \
|
||||
ROLQ $27, rBa; \
|
||||
XORQ rBa, rT1; \
|
||||
MOVQ rT1, _ma(oState); \
|
||||
M_RT1_RCA; \
|
||||
\
|
||||
XORQ rDi, rBo; \
|
||||
ROLQ $15, rBo; \
|
||||
MOVQ rBi, rT1; \
|
||||
ORQ rBo, rT1; \
|
||||
XORQ rBe, rT1; \
|
||||
MOVQ rT1, _me(oState); \
|
||||
M_RT1_RCE; \
|
||||
\
|
||||
XORQ rDo, rBu; \
|
||||
ROLQ $56, rBu; \
|
||||
NOTQ rBo; \
|
||||
MOVQ rBo, rT1; \
|
||||
ORQ rBu, rT1; \
|
||||
XORQ rBi, rT1; \
|
||||
MOVQ rT1, _mi(oState); \
|
||||
\
|
||||
ORQ rBa, rBe; \
|
||||
XORQ rBu, rBe; \
|
||||
MOVQ rBe, _mu(oState); \
|
||||
\
|
||||
ANDQ rBa, rBu; \
|
||||
XORQ rBo, rBu; \
|
||||
MOVQ rBu, _mo(oState); \
|
||||
M_RBE_RCU; \
|
||||
\
|
||||
/* Result s */ \
|
||||
MOVQ _bi(iState), rBa; \
|
||||
MOVQ _go(iState), rBe; \
|
||||
MOVQ _ku(iState), rBi; \
|
||||
XORQ rDi, rBa; \
|
||||
MOVQ _ma(iState), rBo; \
|
||||
ROLQ $62, rBa; \
|
||||
XORQ rDo, rBe; \
|
||||
MOVQ _se(iState), rBu; \
|
||||
ROLQ $55, rBe; \
|
||||
\
|
||||
XORQ rDu, rBi; \
|
||||
MOVQ rBa, rDu; \
|
||||
XORQ rDe, rBu; \
|
||||
ROLQ $2, rBu; \
|
||||
ANDQ rBe, rDu; \
|
||||
XORQ rBu, rDu; \
|
||||
MOVQ rDu, _su(oState); \
|
||||
\
|
||||
ROLQ $39, rBi; \
|
||||
S_RDU_RCU; \
|
||||
NOTQ rBe; \
|
||||
XORQ rDa, rBo; \
|
||||
MOVQ rBe, rDa; \
|
||||
ANDQ rBi, rDa; \
|
||||
XORQ rBa, rDa; \
|
||||
MOVQ rDa, _sa(oState); \
|
||||
S_RDA_RCA; \
|
||||
\
|
||||
ROLQ $41, rBo; \
|
||||
MOVQ rBi, rDe; \
|
||||
ORQ rBo, rDe; \
|
||||
XORQ rBe, rDe; \
|
||||
MOVQ rDe, _se(oState); \
|
||||
S_RDE_RCE; \
|
||||
\
|
||||
MOVQ rBo, rDi; \
|
||||
MOVQ rBu, rDo; \
|
||||
ANDQ rBu, rDi; \
|
||||
ORQ rBa, rDo; \
|
||||
XORQ rBi, rDi; \
|
||||
XORQ rBo, rDo; \
|
||||
MOVQ rDi, _si(oState); \
|
||||
MOVQ rDo, _so(oState) \
|
||||
|
||||
// func keccakF1600(a *[25]uint64)
|
||||
TEXT ·keccakF1600(SB), 0, $200-8
|
||||
MOVQ a+0(FP), rpState
|
||||
|
||||
// Convert the user state into an internal state
|
||||
NOTQ _be(rpState)
|
||||
NOTQ _bi(rpState)
|
||||
NOTQ _go(rpState)
|
||||
NOTQ _ki(rpState)
|
||||
NOTQ _mi(rpState)
|
||||
NOTQ _sa(rpState)
|
||||
|
||||
// Execute the KeccakF permutation
|
||||
MOVQ _ba(rpState), rCa
|
||||
MOVQ _be(rpState), rCe
|
||||
MOVQ _bu(rpState), rCu
|
||||
|
||||
XORQ _ga(rpState), rCa
|
||||
XORQ _ge(rpState), rCe
|
||||
XORQ _gu(rpState), rCu
|
||||
|
||||
XORQ _ka(rpState), rCa
|
||||
XORQ _ke(rpState), rCe
|
||||
XORQ _ku(rpState), rCu
|
||||
|
||||
XORQ _ma(rpState), rCa
|
||||
XORQ _me(rpState), rCe
|
||||
XORQ _mu(rpState), rCu
|
||||
|
||||
XORQ _sa(rpState), rCa
|
||||
XORQ _se(rpState), rCe
|
||||
MOVQ _si(rpState), rDi
|
||||
MOVQ _so(rpState), rDo
|
||||
XORQ _su(rpState), rCu
|
||||
|
||||
mKeccakRound(rpState, rpStack, $0x0000000000000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x0000000000008082, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x800000000000808a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000080008000, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x000000000000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000000008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x000000000000008a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x0000000000000088, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x0000000080008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x000000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x000000008000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x800000000000008b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x8000000000008089, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000000008003, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x8000000000008002, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000000000080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x000000000000800a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x800000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000000008080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpState, rpStack, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
mKeccakRound(rpStack, rpState, $0x8000000080008008, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP)
|
||||
|
||||
// Revert the internal state to the user state
|
||||
NOTQ _be(rpState)
|
||||
NOTQ _bi(rpState)
|
||||
NOTQ _go(rpState)
|
||||
NOTQ _ki(rpState)
|
||||
NOTQ _mi(rpState)
|
||||
NOTQ _sa(rpState)
|
||||
|
||||
RET
|
199
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/sha3.go
generated
vendored
Normal file
199
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/sha3.go
generated
vendored
Normal file
|
@ -0,0 +1,199 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package shake
|
||||
|
||||
import "hash"
|
||||
|
||||
// spongeDirection indicates the direction bytes are flowing through the sponge.
|
||||
type spongeDirection int
|
||||
|
||||
const (
|
||||
// spongeAbsorbing indicates that the sponge is absorbing input.
|
||||
spongeAbsorbing spongeDirection = iota
|
||||
// spongeSqueezing indicates that the sponge is being squeezed.
|
||||
spongeSqueezing
|
||||
)
|
||||
|
||||
const (
|
||||
// maxRate is the maximum size of the internal buffer. SHAKE-256
|
||||
// currently needs the largest buffer.
|
||||
maxRate = 168
|
||||
)
|
||||
|
||||
type state struct {
|
||||
// Generic sponge components.
|
||||
a [25]uint64 // main state of the hash
|
||||
buf []byte // points into storage
|
||||
rate int // the number of bytes of state to use
|
||||
|
||||
// dsbyte contains the "domain separation" bits and the first bit of
|
||||
// the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
|
||||
// SHA-3 and SHAKE functions by appending bitstrings to the message.
|
||||
// Using a little-endian bit-ordering convention, these are "01" for SHA-3
|
||||
// and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the
|
||||
// padding rule from section 5.1 is applied to pad the message to a multiple
|
||||
// of the rate, which involves adding a "1" bit, zero or more "0" bits, and
|
||||
// a final "1" bit. We merge the first "1" bit from the padding into dsbyte,
|
||||
// giving 00000110b (0x06) and 00011111b (0x1f).
|
||||
// [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf
|
||||
// "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and
|
||||
// Extendable-Output Functions (May 2014)"
|
||||
dsbyte byte
|
||||
storage [maxRate]byte
|
||||
|
||||
// Specific to SHA-3 and SHAKE.
|
||||
outputLen int // the default output size in bytes
|
||||
state spongeDirection // whether the sponge is absorbing or squeezing
|
||||
}
|
||||
|
||||
// BlockSize returns the rate of sponge underlying this hash function.
|
||||
func (d *state) BlockSize() int { return d.rate }
|
||||
|
||||
// Size returns the output size of the hash function in bytes.
|
||||
func (d *state) Size() int { return d.outputLen }
|
||||
|
||||
// Reset clears the internal state by zeroing the sponge state and
|
||||
// the byte buffer, and setting Sponge.state to absorbing.
|
||||
func (d *state) Reset() {
|
||||
// Zero the permutation's state.
|
||||
for i := range d.a {
|
||||
d.a[i] = 0
|
||||
}
|
||||
d.state = spongeAbsorbing
|
||||
d.buf = d.storage[:0]
|
||||
}
|
||||
|
||||
func (d *state) clone(ret *state) {
|
||||
// shallow copy
|
||||
*ret = *d
|
||||
// deep copy for a buf
|
||||
if ret.state == spongeAbsorbing {
|
||||
ret.buf = ret.storage[:len(d.buf)]
|
||||
} else {
|
||||
ret.buf = ret.storage[d.rate-len(d.buf) : d.rate]
|
||||
}
|
||||
}
|
||||
|
||||
// permute applies the KeccakF-1600 permutation. It handles
|
||||
// any input-output buffering.
|
||||
func (d *state) permute() {
|
||||
switch d.state {
|
||||
case spongeAbsorbing:
|
||||
// If we're absorbing, we need to xor the input into the state
|
||||
// before applying the permutation.
|
||||
xorIn(d, d.buf)
|
||||
d.buf = d.storage[:0]
|
||||
keccakF1600(&d.a)
|
||||
case spongeSqueezing:
|
||||
// If we're squeezing, we need to apply the permutatin before
|
||||
// copying more output.
|
||||
keccakF1600(&d.a)
|
||||
d.buf = d.storage[:d.rate]
|
||||
copyOut(d, d.buf)
|
||||
}
|
||||
}
|
||||
|
||||
// pads appends the domain separation bits in dsbyte, applies
|
||||
// the multi-bitrate 10..1 padding rule, and permutes the state.
|
||||
func (d *state) padAndPermute(dsbyte byte) {
|
||||
if d.buf == nil {
|
||||
d.buf = d.storage[:0]
|
||||
}
|
||||
// Pad with this instance's domain-separator bits. We know that there's
|
||||
// at least one byte of space in d.buf because, if it were full,
|
||||
// permute would have been called to empty it. dsbyte also contains the
|
||||
// first one bit for the padding. See the comment in the state struct.
|
||||
d.buf = append(d.buf, dsbyte)
|
||||
zerosStart := len(d.buf)
|
||||
d.buf = d.storage[:d.rate]
|
||||
for i := zerosStart; i < d.rate; i++ {
|
||||
d.buf[i] = 0
|
||||
}
|
||||
// This adds the final one bit for the padding. Because of the way that
|
||||
// bits are numbered from the LSB upwards, the final bit is the MSB of
|
||||
// the last byte.
|
||||
d.buf[d.rate-1] ^= 0x80
|
||||
// Apply the permutation
|
||||
d.permute()
|
||||
d.state = spongeSqueezing
|
||||
d.buf = d.storage[:d.rate]
|
||||
copyOut(d, d.buf)
|
||||
}
|
||||
|
||||
// Write absorbs more data into the hash's state. It produces an error
|
||||
// if more data is written to the ShakeHash after writing
|
||||
func (d *state) Write(p []byte) (int, error) {
|
||||
if d.state != spongeAbsorbing {
|
||||
panic("shake: write to sponge after read")
|
||||
}
|
||||
if d.buf == nil {
|
||||
d.buf = d.storage[:0]
|
||||
}
|
||||
written := len(p)
|
||||
|
||||
for len(p) > 0 {
|
||||
if len(d.buf) == 0 && len(p) >= d.rate {
|
||||
// The fast path; absorb a full "rate" bytes of input and apply the permutation.
|
||||
xorIn(d, p[:d.rate])
|
||||
p = p[d.rate:]
|
||||
keccakF1600(&d.a)
|
||||
} else {
|
||||
// The slow path; buffer the input until we can fill the sponge, and then xor it in.
|
||||
todo := d.rate - len(d.buf)
|
||||
if todo > len(p) {
|
||||
todo = len(p)
|
||||
}
|
||||
d.buf = append(d.buf, p[:todo]...)
|
||||
p = p[todo:]
|
||||
|
||||
// If the sponge is full, apply the permutation.
|
||||
if len(d.buf) == d.rate {
|
||||
d.permute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return written, nil
|
||||
}
|
||||
|
||||
// Read squeezes an arbitrary number of bytes from the sponge.
|
||||
func (d *state) Read(out []byte) (n int, err error) {
|
||||
// If we're still absorbing, pad and apply the permutation.
|
||||
if d.state == spongeAbsorbing {
|
||||
d.padAndPermute(d.dsbyte)
|
||||
}
|
||||
|
||||
n = len(out)
|
||||
|
||||
// Now, do the squeezing.
|
||||
for len(out) > 0 {
|
||||
n := copy(out, d.buf)
|
||||
d.buf = d.buf[n:]
|
||||
out = out[n:]
|
||||
|
||||
// Apply the permutation if we've squeezed the sponge dry.
|
||||
if len(d.buf) == 0 {
|
||||
d.permute()
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Sum applies padding to the hash state and then squeezes out the desired
|
||||
// number of output bytes.
|
||||
func (d *state) Sum(in []byte) []byte {
|
||||
// Make a copy of the original hash so that caller can keep writing
|
||||
// and summing.
|
||||
var dup state
|
||||
d.clone(&dup)
|
||||
hash := make([]byte, dup.outputLen)
|
||||
dup.Read(hash)
|
||||
return append(in, hash...)
|
||||
}
|
||||
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New256 instead.
|
||||
func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} }
|
134
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/shake.go
generated
vendored
Normal file
134
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/shake.go
generated
vendored
Normal file
|
@ -0,0 +1,134 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package shake
|
||||
|
||||
// This file defines the CShake struct, and provides
|
||||
// functions for creating SHAKE and cSHAKE instances, as well as utility
|
||||
// functions for hashing bytes to arbitrary-length output.
|
||||
//
|
||||
//
|
||||
// SHAKE implementation is based on FIPS PUB 202 [1]
|
||||
// cSHAKE implementations is based on NIST SP 800-185 [2]
|
||||
//
|
||||
// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
|
||||
// [2] https://doi.org/10.6028/NIST.SP.800-185
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// cSHAKE specific context
|
||||
type CShake struct {
|
||||
state // SHA-3 state context and Read/Write operations
|
||||
|
||||
// initBlock is the cSHAKE specific initialization set of bytes. It is initialized
|
||||
// by newCShake function and stores concatenation of N followed by S, encoded
|
||||
// by the method specified in 3.3 of [1].
|
||||
// It is stored here in order for Reset() to be able to put context into
|
||||
// initial state.
|
||||
initBlock []byte
|
||||
}
|
||||
|
||||
// Consts for configuring initial SHA-3 state
|
||||
const (
|
||||
dsbyteShake = 0x1f
|
||||
dsbyteCShake = 0x04
|
||||
rate128 = 168
|
||||
rate256 = 136
|
||||
)
|
||||
|
||||
func bytepad(input []byte, w int) []byte {
|
||||
// leftEncode always returns max 9 bytes
|
||||
buf := make([]byte, 0, 9+len(input)+w)
|
||||
buf = append(buf, leftEncode(uint64(w))...)
|
||||
buf = append(buf, input...)
|
||||
padlen := w - (len(buf) % w)
|
||||
return append(buf, make([]byte, padlen)...)
|
||||
}
|
||||
|
||||
func leftEncode(value uint64) []byte {
|
||||
var b [9]byte
|
||||
binary.BigEndian.PutUint64(b[1:], value)
|
||||
// Trim all but last leading zero bytes
|
||||
i := byte(1)
|
||||
for i < 8 && b[i] == 0 {
|
||||
i++
|
||||
}
|
||||
// Prepend number of encoded bytes
|
||||
b[i-1] = 9 - i
|
||||
return b[i-1:]
|
||||
}
|
||||
|
||||
func newCShake(N, S []byte, rate int, dsbyte byte) *CShake {
|
||||
|
||||
// leftEncode returns max 9 bytes
|
||||
initBlock := make([]byte, 0, 9*2+len(N)+len(S))
|
||||
initBlock = append(initBlock, leftEncode(uint64(len(N)*8))...)
|
||||
initBlock = append(initBlock, N...)
|
||||
initBlock = append(initBlock, leftEncode(uint64(len(S)*8))...)
|
||||
initBlock = append(initBlock, S...)
|
||||
|
||||
c := CShake{
|
||||
state: state{rate: rate, dsbyte: dsbyte},
|
||||
initBlock: bytepad(initBlock, rate),
|
||||
}
|
||||
c.Write(c.initBlock)
|
||||
return &c
|
||||
}
|
||||
|
||||
// Reset resets the hash to initial state.
|
||||
func (c *CShake) Reset() {
|
||||
c.state.Reset()
|
||||
c.Write(c.initBlock)
|
||||
}
|
||||
|
||||
// Clone returns copy of a cSHAKE context within its current state.
|
||||
func (c *CShake) Clone() CShake {
|
||||
var ret CShake
|
||||
c.clone(&ret.state)
|
||||
ret.initBlock = make([]byte, len(c.initBlock))
|
||||
copy(ret.initBlock, c.initBlock)
|
||||
return ret
|
||||
}
|
||||
|
||||
// NewShake128 creates a new SHAKE128 variable-output-length CShake.
|
||||
// Its generic security strength is 128 bits against all attacks if at
|
||||
// least 32 bytes of its output are used.
|
||||
func NewShake128() *CShake {
|
||||
return &CShake{state{rate: rate128, dsbyte: dsbyteShake}, nil}
|
||||
}
|
||||
|
||||
// NewShake256 creates a new SHAKE256 variable-output-length CShake.
|
||||
// Its generic security strength is 256 bits against all attacks if
|
||||
// at least 64 bytes of its output are used.
|
||||
func NewShake256() *CShake {
|
||||
return &CShake{state{rate: rate256, dsbyte: dsbyteShake}, nil}
|
||||
}
|
||||
|
||||
// NewCShake128 creates a new instance of cSHAKE128 variable-output-length CShake,
|
||||
// a customizable variant of SHAKE128.
|
||||
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
|
||||
// desired. S is a customization byte string used for domain separation - two cSHAKE
|
||||
// computations on same input with different S yield unrelated outputs.
|
||||
// When N and S are both empty, this is equivalent to NewShake128.
|
||||
func NewCShake128(N, S []byte) *CShake {
|
||||
if len(N) == 0 && len(S) == 0 {
|
||||
return NewShake128()
|
||||
}
|
||||
return newCShake(N, S, rate128, dsbyteCShake)
|
||||
}
|
||||
|
||||
// NewCShake256 creates a new instance of cSHAKE256 variable-output-length CShake,
|
||||
// a customizable variant of SHAKE256.
|
||||
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
|
||||
// desired. S is a customization byte string used for domain separation - two cSHAKE
|
||||
// computations on same input with different S yield unrelated outputs.
|
||||
// When N and S are both empty, this is equivalent to NewShake256.
|
||||
func NewCShake256(N, S []byte) *CShake {
|
||||
if len(N) == 0 && len(S) == 0 {
|
||||
return NewShake256()
|
||||
}
|
||||
return newCShake(N, S, rate256, dsbyteCShake)
|
||||
}
|
30
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/xor_generic.go
generated
vendored
Normal file
30
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/xor_generic.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !amd64,!386,!ppc64le
|
||||
|
||||
package shake
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// xorInGeneric xors the bytes in buf into the state; it
|
||||
// makes no non-portable assumptions about memory layout
|
||||
// or alignment.
|
||||
func xorIn(d *state, buf []byte) {
|
||||
n := len(buf) / 8
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
a := binary.LittleEndian.Uint64(buf)
|
||||
d.a[i] ^= a
|
||||
buf = buf[8:]
|
||||
}
|
||||
}
|
||||
|
||||
// copyOutGeneric copies ulint64s to a byte buffer.
|
||||
func copyOut(d *state, b []byte) {
|
||||
for i := 0; len(b) >= 8; i++ {
|
||||
binary.LittleEndian.PutUint64(b, d.a[i])
|
||||
b = b[8:]
|
||||
}
|
||||
}
|
51
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/xor_unaligned.go
generated
vendored
Normal file
51
vendor/github.com/cloudflare/circl/dh/sidh/internal/shake/xor_unaligned.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64 386 ppc64le
|
||||
// +build !appengine
|
||||
|
||||
package shake
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func xorIn(d *state, buf []byte) {
|
||||
bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))
|
||||
n := len(buf)
|
||||
if n >= 72 {
|
||||
d.a[0] ^= bw[0]
|
||||
d.a[1] ^= bw[1]
|
||||
d.a[2] ^= bw[2]
|
||||
d.a[3] ^= bw[3]
|
||||
d.a[4] ^= bw[4]
|
||||
d.a[5] ^= bw[5]
|
||||
d.a[6] ^= bw[6]
|
||||
d.a[7] ^= bw[7]
|
||||
d.a[8] ^= bw[8]
|
||||
}
|
||||
if n >= 104 {
|
||||
d.a[9] ^= bw[9]
|
||||
d.a[10] ^= bw[10]
|
||||
d.a[11] ^= bw[11]
|
||||
d.a[12] ^= bw[12]
|
||||
}
|
||||
if n >= 136 {
|
||||
d.a[13] ^= bw[13]
|
||||
d.a[14] ^= bw[14]
|
||||
d.a[15] ^= bw[15]
|
||||
d.a[16] ^= bw[16]
|
||||
}
|
||||
if n >= 144 {
|
||||
d.a[17] ^= bw[17]
|
||||
}
|
||||
if n >= 168 {
|
||||
d.a[18] ^= bw[18]
|
||||
d.a[19] ^= bw[19]
|
||||
d.a[20] ^= bw[20]
|
||||
}
|
||||
}
|
||||
|
||||
func copyOut(d *state, buf []byte) {
|
||||
ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0]))
|
||||
copy(buf, ab[:])
|
||||
}
|
|
@ -0,0 +1,267 @@
|
|||
package sidh
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/p503"
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/p751"
|
||||
)
|
||||
|
||||
// I keep it bool in order to be able to apply logical NOT
|
||||
type KeyVariant uint
|
||||
|
||||
// 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 *common.SidhParams
|
||||
// Flag indicates wether corresponds to 2-, 3-torsion group or SIKE
|
||||
keyVariant KeyVariant
|
||||
}
|
||||
|
||||
// Defines operations on public key
|
||||
type PublicKey struct {
|
||||
key
|
||||
// x-coordinates of P,Q,P-Q in this exact order
|
||||
affine3Pt [3]common.Fp2
|
||||
}
|
||||
|
||||
// Defines operations on private key
|
||||
type PrivateKey struct {
|
||||
key
|
||||
// Secret key
|
||||
Scalar []byte
|
||||
// Used only by KEM
|
||||
S []byte
|
||||
}
|
||||
|
||||
// Id's correspond to bitlength of the prime field characteristic
|
||||
// Currently Fp751 is the only one supported by this implementation
|
||||
const (
|
||||
Fp503 = common.Fp503
|
||||
Fp751 = common.Fp751
|
||||
)
|
||||
|
||||
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
|
||||
KeyVariantSidhA KeyVariant = 1 << 0
|
||||
// 010 - SIDH: corresponds to 3-torsion group
|
||||
KeyVariantSidhB = 1 << 1
|
||||
// 110 - SIKE
|
||||
KeyVariantSike = 1<<2 | KeyVariantSidhB
|
||||
)
|
||||
|
||||
// Accessor to key variant
|
||||
func (key *key) Variant() KeyVariant {
|
||||
return key.keyVariant
|
||||
}
|
||||
|
||||
// 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: common.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")
|
||||
}
|
||||
ssSz := pub.params.SharedSecretSize
|
||||
common.BytesToFp2(&pub.affine3Pt[0], input[0:ssSz], pub.params.Bytelen)
|
||||
common.BytesToFp2(&pub.affine3Pt[1], input[ssSz:2*ssSz], pub.params.Bytelen)
|
||||
common.BytesToFp2(&pub.affine3Pt[2], input[2*ssSz:3*ssSz], pub.params.Bytelen)
|
||||
switch pub.params.ID {
|
||||
case Fp503:
|
||||
p503.ToMontgomery(&pub.affine3Pt[0], &pub.affine3Pt[0])
|
||||
p503.ToMontgomery(&pub.affine3Pt[1], &pub.affine3Pt[1])
|
||||
p503.ToMontgomery(&pub.affine3Pt[2], &pub.affine3Pt[2])
|
||||
case Fp751:
|
||||
p751.ToMontgomery(&pub.affine3Pt[0], &pub.affine3Pt[0])
|
||||
p751.ToMontgomery(&pub.affine3Pt[1], &pub.affine3Pt[1])
|
||||
p751.ToMontgomery(&pub.affine3Pt[2], &pub.affine3Pt[2])
|
||||
default:
|
||||
panic("Unsupported key")
|
||||
}
|
||||
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(out []byte) {
|
||||
var feTmp [3]common.Fp2
|
||||
ssSz := pub.params.SharedSecretSize
|
||||
switch pub.params.ID {
|
||||
case Fp503:
|
||||
p503.FromMontgomery(&feTmp[0], &pub.affine3Pt[0])
|
||||
p503.FromMontgomery(&feTmp[1], &pub.affine3Pt[1])
|
||||
p503.FromMontgomery(&feTmp[2], &pub.affine3Pt[2])
|
||||
case Fp751:
|
||||
p751.FromMontgomery(&feTmp[0], &pub.affine3Pt[0])
|
||||
p751.FromMontgomery(&feTmp[1], &pub.affine3Pt[1])
|
||||
p751.FromMontgomery(&feTmp[2], &pub.affine3Pt[2])
|
||||
default:
|
||||
panic("Unsupported key")
|
||||
}
|
||||
common.Fp2ToBytes(out[0:ssSz], &feTmp[0], pub.params.Bytelen)
|
||||
common.Fp2ToBytes(out[ssSz:2*ssSz], &feTmp[1], pub.params.Bytelen)
|
||||
common.Fp2ToBytes(out[2*ssSz:3*ssSz], &feTmp[2], pub.params.Bytelen)
|
||||
}
|
||||
|
||||
// Size returns size of the public key in bytes
|
||||
func (pub *PublicKey) Size() int {
|
||||
return pub.params.PublicKeySize
|
||||
}
|
||||
|
||||
// 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: common.Params(id), keyVariant: v}}
|
||||
if (v & KeyVariantSidhA) == KeyVariantSidhA {
|
||||
prv.Scalar = make([]byte, prv.params.A.SecretByteLen)
|
||||
} else {
|
||||
prv.Scalar = make([]byte, prv.params.B.SecretByteLen)
|
||||
}
|
||||
if v == KeyVariantSike {
|
||||
prv.S = make([]byte, prv.params.MsgLen)
|
||||
}
|
||||
return prv
|
||||
}
|
||||
|
||||
// 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(out []byte) {
|
||||
copy(out, prv.S)
|
||||
copy(out[len(prv.S):], prv.Scalar)
|
||||
}
|
||||
|
||||
// Size returns size of the private key in bytes
|
||||
func (prv *PrivateKey) Size() int {
|
||||
tmp := len(prv.Scalar)
|
||||
if prv.Variant() == KeyVariantSike {
|
||||
tmp += prv.params.MsgLen
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
// Size returns size of the shared secret
|
||||
func (prv *PrivateKey) SharedSecretSize() int {
|
||||
return prv.params.SharedSecretSize
|
||||
}
|
||||
|
||||
// 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 dp *common.DomainParams
|
||||
|
||||
if (prv.keyVariant & KeyVariantSidhA) == KeyVariantSidhA {
|
||||
dp = &prv.params.A
|
||||
} else {
|
||||
dp = &prv.params.B
|
||||
}
|
||||
|
||||
if prv.keyVariant == KeyVariantSike {
|
||||
if _, err := io.ReadFull(rand, prv.S); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 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>. Similarly for the last byte, but generation
|
||||
// needs to chop off some bits, to make sure generated value is an element of
|
||||
// a key-space.
|
||||
if _, err := io.ReadFull(rand, prv.Scalar); 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 comfortable 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 nil
|
||||
}
|
||||
|
||||
// Generates public key.
|
||||
func (prv *PrivateKey) GeneratePublicKey(pub *PublicKey) {
|
||||
var isA = (prv.keyVariant & KeyVariantSidhA) == KeyVariantSidhA
|
||||
|
||||
if (pub.keyVariant != prv.keyVariant) || (pub.params.ID != prv.params.ID) {
|
||||
panic("sidh: incompatbile public key")
|
||||
}
|
||||
|
||||
switch prv.params.ID {
|
||||
case Fp503:
|
||||
if isA {
|
||||
p503.PublicKeyGenA(&pub.affine3Pt, prv.Scalar)
|
||||
} else {
|
||||
p503.PublicKeyGenB(&pub.affine3Pt, prv.Scalar)
|
||||
}
|
||||
case Fp751:
|
||||
if isA {
|
||||
p751.PublicKeyGenA(&pub.affine3Pt, prv.Scalar)
|
||||
} else {
|
||||
p751.PublicKeyGenB(&pub.affine3Pt, prv.Scalar)
|
||||
}
|
||||
default:
|
||||
panic("Field not supported")
|
||||
}
|
||||
}
|
||||
|
||||
// Computes a SIDH shared secret. 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.
|
||||
//
|
||||
// Caller must make sure key SIDH key pair is not used more than once.
|
||||
func (prv *PrivateKey) DeriveSecret(ss []byte, pub *PublicKey) {
|
||||
var isA = (prv.keyVariant & KeyVariantSidhA) == KeyVariantSidhA
|
||||
|
||||
if (pub.keyVariant == prv.keyVariant) || (pub.params.ID != prv.params.ID) {
|
||||
panic("sidh: public and private are incompatbile")
|
||||
}
|
||||
|
||||
switch prv.params.ID {
|
||||
case Fp503:
|
||||
if isA {
|
||||
p503.DeriveSecretA(ss, prv.Scalar, &pub.affine3Pt)
|
||||
} else {
|
||||
p503.DeriveSecretB(ss, prv.Scalar, &pub.affine3Pt)
|
||||
}
|
||||
case Fp751:
|
||||
if isA {
|
||||
p751.DeriveSecretA(ss, prv.Scalar, &pub.affine3Pt)
|
||||
} else {
|
||||
p751.DeriveSecretB(ss, prv.Scalar, &pub.affine3Pt)
|
||||
}
|
||||
default:
|
||||
panic("Field not supported")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
package sidh
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/common"
|
||||
"github.com/cloudflare/circl/dh/sidh/internal/shake"
|
||||
)
|
||||
|
||||
// SIKE KEM interface
|
||||
type KEM struct {
|
||||
allocated bool
|
||||
rng io.Reader
|
||||
msg []byte
|
||||
secretBytes []byte
|
||||
params *common.SidhParams
|
||||
cshakeG, cshakeH, cshakeF *shake.CShake
|
||||
}
|
||||
|
||||
// NewSike503 instantiates SIKE/p503 KEM
|
||||
func NewSike503(rng io.Reader) *KEM {
|
||||
var c KEM
|
||||
c.Allocate(Fp503, rng)
|
||||
return &c
|
||||
}
|
||||
|
||||
// NewSike751 instantiates SIKE/p751 KEM
|
||||
func NewSike751(rng io.Reader) *KEM {
|
||||
var c KEM
|
||||
c.Allocate(Fp751, rng)
|
||||
return &c
|
||||
}
|
||||
|
||||
// Allocate allocates KEM object for multiple SIKE operations. The rng
|
||||
// must be cryptographically secure PRNG.
|
||||
func (c *KEM) Allocate(id uint8, rng io.Reader) {
|
||||
// Constants used for cSHAKE customization
|
||||
// Those values are different than in [SIKE] - they are encoded on 16bits. This is
|
||||
// done in order for implementation to be compatible with [REF] and test vectors.
|
||||
var G = []byte{0x00, 0x00}
|
||||
var H = []byte{0x01, 0x00}
|
||||
var F = []byte{0x02, 0x00}
|
||||
|
||||
c.cshakeG = shake.NewCShake256(nil, G)
|
||||
c.cshakeH = shake.NewCShake256(nil, H)
|
||||
c.cshakeF = shake.NewCShake256(nil, F)
|
||||
c.rng = rng
|
||||
c.params = common.Params(id)
|
||||
c.msg = make([]byte, c.params.MsgLen)
|
||||
c.secretBytes = make([]byte, c.params.A.SecretByteLen)
|
||||
c.allocated = true
|
||||
}
|
||||
|
||||
// Encapsulate receives the public key and generates SIKE ciphertext and shared secret.
|
||||
// The generated ciphertext is used for authentication.
|
||||
// Error is returned in case PRNG fails. Function panics in case wrongly formated
|
||||
// input was provided.
|
||||
func (c *KEM) Encapsulate(ciphertext, secret []byte, pub *PublicKey) error {
|
||||
if !c.allocated {
|
||||
panic("KEM unallocated")
|
||||
}
|
||||
|
||||
if KeyVariantSike != pub.keyVariant {
|
||||
panic("Wrong type of public key")
|
||||
}
|
||||
|
||||
if len(secret) < c.SharedSecretSize() {
|
||||
panic("shared secret buffer to small")
|
||||
}
|
||||
|
||||
if len(ciphertext) < c.CiphertextSize() {
|
||||
panic("ciphertext buffer to small")
|
||||
}
|
||||
|
||||
// Generate ephemeral value
|
||||
_, err := io.ReadFull(c.rng, c.msg[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var buf [3 * common.MaxSharedSecretBsz]byte
|
||||
var skA = PrivateKey{
|
||||
key: key{
|
||||
params: c.params,
|
||||
keyVariant: KeyVariantSidhA},
|
||||
Scalar: c.secretBytes}
|
||||
var pkA = NewPublicKey(c.params.ID, KeyVariantSidhA)
|
||||
|
||||
pub.Export(buf[:])
|
||||
c.cshakeG.Reset()
|
||||
c.cshakeG.Write(c.msg)
|
||||
c.cshakeG.Write(buf[:3*c.params.SharedSecretSize])
|
||||
c.cshakeG.Read(skA.Scalar)
|
||||
|
||||
// Ensure bitlength is not bigger then to 2^e2-1
|
||||
skA.Scalar[len(skA.Scalar)-1] &= (1 << (c.params.A.SecretBitLen % 8)) - 1
|
||||
skA.GeneratePublicKey(pkA)
|
||||
c.generateCiphertext(ciphertext, &skA, pkA, pub, c.msg[:])
|
||||
|
||||
// K = H(msg||(c0||c1))
|
||||
c.cshakeH.Reset()
|
||||
c.cshakeH.Write(c.msg)
|
||||
c.cshakeH.Write(ciphertext)
|
||||
c.cshakeH.Read(secret[:c.SharedSecretSize()])
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decapsulate given the keypair and ciphertext as inputs, Decapsulate outputs a shared
|
||||
// secret if plaintext verifies correctly, otherwise function outputs random value.
|
||||
// Decapsulation may panic in case input is wrongly formated, in particular, size of
|
||||
// the 'ciphertext' must be exactly equal to c.CiphertextSize().
|
||||
func (c *KEM) Decapsulate(secret []byte, prv *PrivateKey, pub *PublicKey, ciphertext []byte) error {
|
||||
if !c.allocated {
|
||||
panic("KEM unallocated")
|
||||
}
|
||||
|
||||
if KeyVariantSike != pub.keyVariant {
|
||||
panic("Wrong type of public key")
|
||||
}
|
||||
|
||||
if pub.keyVariant != prv.keyVariant {
|
||||
panic("Public and private key are of different type")
|
||||
}
|
||||
|
||||
if len(secret) < c.SharedSecretSize() {
|
||||
panic("shared secret buffer to small")
|
||||
}
|
||||
|
||||
if len(ciphertext) != c.CiphertextSize() {
|
||||
panic("ciphertext buffer to small")
|
||||
}
|
||||
|
||||
var m [common.MaxMsgBsz]byte
|
||||
var r [common.MaxSidhPrivateKeyBsz]byte
|
||||
var pkBytes [3 * common.MaxSharedSecretBsz]byte
|
||||
var skA = PrivateKey{
|
||||
key: key{
|
||||
params: c.params,
|
||||
keyVariant: KeyVariantSidhA},
|
||||
Scalar: c.secretBytes}
|
||||
var pkA = NewPublicKey(c.params.ID, KeyVariantSidhA)
|
||||
c1Len := c.decrypt(m[:], prv, ciphertext)
|
||||
|
||||
// r' = G(m'||pub)
|
||||
pub.Export(pkBytes[:])
|
||||
c.cshakeG.Reset()
|
||||
c.cshakeG.Write(m[:c1Len])
|
||||
c.cshakeG.Write(pkBytes[:3*c.params.SharedSecretSize])
|
||||
c.cshakeG.Read(r[:c.params.A.SecretByteLen])
|
||||
// Ensure bitlength is not bigger than 2^e2-1
|
||||
r[c.params.A.SecretByteLen-1] &= (1 << (c.params.A.SecretBitLen % 8)) - 1
|
||||
|
||||
// Never fails
|
||||
skA.Import(r[:c.params.A.SecretByteLen])
|
||||
skA.GeneratePublicKey(pkA)
|
||||
pkA.Export(pkBytes[:])
|
||||
|
||||
// S is chosen at random when generating a key and unknown to other party. It is
|
||||
// important that S is unpredictable to the other party. Without this check, would
|
||||
// be possible to recover a secret, by providing series of invalid ciphertexts.
|
||||
//
|
||||
// See more details in "On the security of supersingular isogeny cryptosystems"
|
||||
// (S. Galbraith, et al., 2016, ePrint #859).
|
||||
mask := subtle.ConstantTimeCompare(pkBytes[:c.params.PublicKeySize], ciphertext[:pub.params.PublicKeySize])
|
||||
common.Cpick(mask, m[:c1Len], m[:c1Len], prv.S)
|
||||
c.cshakeH.Reset()
|
||||
c.cshakeH.Write(m[:c1Len])
|
||||
c.cshakeH.Write(ciphertext)
|
||||
c.cshakeH.Read(secret[:c.SharedSecretSize()])
|
||||
return nil
|
||||
}
|
||||
|
||||
// Resets internal state of KEM. Function should be used
|
||||
// after Allocate and between subsequent calls to Encapsulate
|
||||
// and/or Decapsulate.
|
||||
func (c *KEM) Reset() {
|
||||
for i := range c.msg {
|
||||
c.msg[i] = 0
|
||||
}
|
||||
|
||||
for i := range c.secretBytes {
|
||||
c.secretBytes[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Returns size of resulting ciphertext
|
||||
func (c *KEM) CiphertextSize() int {
|
||||
return c.params.CiphertextSize
|
||||
}
|
||||
|
||||
// Returns size of resulting shared secret
|
||||
func (c *KEM) SharedSecretSize() int {
|
||||
return c.params.KemSize
|
||||
}
|
||||
|
||||
func (c *KEM) generateCiphertext(ctext []byte, skA *PrivateKey, pkA, pkB *PublicKey, ptext []byte) {
|
||||
var n [common.MaxMsgBsz]byte
|
||||
var j [common.MaxSharedSecretBsz]byte
|
||||
var ptextLen = skA.params.MsgLen
|
||||
|
||||
skA.DeriveSecret(j[:], pkB)
|
||||
c.cshakeF.Reset()
|
||||
c.cshakeF.Write(j[:skA.params.SharedSecretSize])
|
||||
c.cshakeF.Read(n[:ptextLen])
|
||||
for i := range ptext {
|
||||
n[i] ^= ptext[i]
|
||||
}
|
||||
|
||||
pkA.Export(ctext)
|
||||
copy(ctext[pkA.Size():], n[:ptextLen])
|
||||
}
|
||||
|
||||
// encrypt uses SIKE public key to encrypt plaintext. Requires cryptographically secure
|
||||
// PRNG. Returns ciphertext in case encryption succeeds. Returns error in case PRNG fails
|
||||
// or wrongly formated input was provided.
|
||||
func (c *KEM) encrypt(ctext []byte, rng io.Reader, pub *PublicKey, ptext []byte) error {
|
||||
var ptextLen = len(ptext)
|
||||
// c1 must be security level + 64 bits (see [SIKE] 1.4 and 4.3.3)
|
||||
if ptextLen != (pub.params.KemSize + 8) {
|
||||
return errors.New("unsupported message length")
|
||||
}
|
||||
|
||||
skA := NewPrivateKey(pub.params.ID, KeyVariantSidhA)
|
||||
pkA := NewPublicKey(pub.params.ID, KeyVariantSidhA)
|
||||
err := skA.Generate(rng)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
skA.GeneratePublicKey(pkA)
|
||||
c.generateCiphertext(ctext, skA, pkA, pub, ptext)
|
||||
return nil
|
||||
}
|
||||
|
||||
// decrypt uses SIKE private key to decrypt ciphertext. Returns plaintext in case
|
||||
// decryption succeeds or error in case unexptected input was provided.
|
||||
// Constant time
|
||||
func (c *KEM) decrypt(n []byte, prv *PrivateKey, ctext []byte) int {
|
||||
var c1Len int
|
||||
var j [common.MaxSharedSecretBsz]byte
|
||||
var pkLen = prv.params.PublicKeySize
|
||||
|
||||
// ctext is a concatenation of (ciphertext = pubkey_A || c1)
|
||||
// it must be security level + 64 bits (see [SIKE] 1.4 and 4.3.3)
|
||||
// Lengths has been already checked by Decapsulate()
|
||||
c1Len = len(ctext) - pkLen
|
||||
c0 := NewPublicKey(prv.params.ID, KeyVariantSidhA)
|
||||
// Never fails
|
||||
c0.Import(ctext[:pkLen])
|
||||
prv.DeriveSecret(j[:], c0)
|
||||
c.cshakeF.Reset()
|
||||
c.cshakeF.Write(j[:prv.params.SharedSecretSize])
|
||||
c.cshakeF.Read(n[:c1Len])
|
||||
for i := range n[:c1Len] {
|
||||
n[i] ^= ctext[pkLen+i]
|
||||
}
|
||||
return c1Len
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License
|
||||
|
||||
Copyright (c) 2019-2020, Cloudflare, Inc. and Apple, Inc. 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.
|
|
@ -0,0 +1,20 @@
|
|||
# odoh-go
|
||||
|
||||
[](https://coveralls.io/github/cloudflare/odoh-go?branch=master)
|
||||
[](https://godoc.org/github.com/cloudflare/odoh-go)
|
||||
|
||||
This library implements draft -03 of [Oblivious DoH](https://tools.ietf.org/html/draft-pauly-dprive-oblivious-doh-03). It is based on the original implementation [available here](https://github.com/chris-wood/odoh).
|
||||
|
||||
## Test vector generation
|
||||
|
||||
To generate test vectors, run:
|
||||
|
||||
```
|
||||
$ ODOH_TEST_VECTORS_OUT=test-vectors.json go test -v -run TestVectorGenerate
|
||||
```
|
||||
|
||||
To check test vectors, run:
|
||||
|
||||
```
|
||||
$ ODOH_TEST_VECTORS_IN=test-vectors.json go test -v -run TestVectorVerify
|
||||
```
|
|
@ -0,0 +1,47 @@
|
|||
// The MIT License
|
||||
//
|
||||
// Copyright (c) 2019-2020, Cloudflare, Inc. and Apple, Inc. 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.
|
||||
|
||||
package odoh
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func encodeLengthPrefixedSlice(slice []byte) []byte {
|
||||
result := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(result, uint16(len(slice)))
|
||||
return append(result, slice...)
|
||||
}
|
||||
|
||||
func decodeLengthPrefixedSlice(slice []byte) ([]byte, int, error) {
|
||||
if len(slice) < 2 {
|
||||
return nil, 0, fmt.Errorf("Expected at least 2 bytes of length encoded prefix")
|
||||
}
|
||||
|
||||
length := binary.BigEndian.Uint16(slice)
|
||||
if int(2+length) > len(slice) {
|
||||
return nil, 0, fmt.Errorf("Insufficient data. Expected %d, got %d", 2+length, len(slice))
|
||||
}
|
||||
|
||||
return slice[2 : 2+length], int(2 + length), nil
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module github.com/cloudflare/odoh-go
|
||||
|
||||
go 1.14
|
||||
|
||||
require github.com/cisco/go-hpke v0.0.0-20201023221920-2866d2aa0603
|
|
@ -0,0 +1,176 @@
|
|||
// The MIT License
|
||||
//
|
||||
// Copyright (c) 2019-2020, Cloudflare, Inc. and Apple, Inc. 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.
|
||||
|
||||
package odoh
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ObliviousMessageType uint8
|
||||
|
||||
const (
|
||||
QueryType ObliviousMessageType = 0x01
|
||||
ResponseType ObliviousMessageType = 0x02
|
||||
)
|
||||
|
||||
//
|
||||
// struct {
|
||||
// opaque dns_message<1..2^16-1>;
|
||||
// opaque padding<0..2^16-1>;
|
||||
// } ObliviousDoHQueryBody;
|
||||
//
|
||||
type ObliviousDNSMessageBody struct {
|
||||
DnsMessage []byte
|
||||
Padding []byte
|
||||
}
|
||||
|
||||
func (m ObliviousDNSMessageBody) Marshal() []byte {
|
||||
return append(encodeLengthPrefixedSlice(m.DnsMessage), encodeLengthPrefixedSlice(m.Padding)...)
|
||||
}
|
||||
|
||||
func UnmarshalMessageBody(data []byte) (ObliviousDNSMessageBody, error) {
|
||||
messageLength := binary.BigEndian.Uint16(data)
|
||||
if int(2+messageLength) > len(data) {
|
||||
return ObliviousDNSMessageBody{}, fmt.Errorf("Invalid DNS message length")
|
||||
}
|
||||
message := data[2 : 2+messageLength]
|
||||
|
||||
paddingLength := binary.BigEndian.Uint16(data[2+messageLength:])
|
||||
if int(2+messageLength+2+paddingLength) > len(data) {
|
||||
return ObliviousDNSMessageBody{}, fmt.Errorf("Invalid DNS padding length")
|
||||
}
|
||||
|
||||
padding := data[2+messageLength+2 : 2+messageLength+2+paddingLength]
|
||||
return ObliviousDNSMessageBody{
|
||||
DnsMessage: message,
|
||||
Padding: padding,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m ObliviousDNSMessageBody) Message() []byte {
|
||||
return m.DnsMessage
|
||||
}
|
||||
|
||||
type ObliviousDNSQuery struct {
|
||||
ObliviousDNSMessageBody
|
||||
}
|
||||
|
||||
func CreateObliviousDNSQuery(query []byte, paddingBytes uint16) *ObliviousDNSQuery {
|
||||
msg := ObliviousDNSMessageBody{
|
||||
DnsMessage: query,
|
||||
Padding: make([]byte, int(paddingBytes)),
|
||||
}
|
||||
return &ObliviousDNSQuery{
|
||||
msg,
|
||||
}
|
||||
}
|
||||
|
||||
func UnmarshalQueryBody(data []byte) (*ObliviousDNSQuery, error) {
|
||||
msg, err := UnmarshalMessageBody(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ObliviousDNSQuery{msg}, nil
|
||||
}
|
||||
|
||||
type ObliviousDNSResponse struct {
|
||||
ObliviousDNSMessageBody
|
||||
}
|
||||
|
||||
func CreateObliviousDNSResponse(response []byte, paddingBytes uint16) *ObliviousDNSResponse {
|
||||
msg := ObliviousDNSMessageBody{
|
||||
DnsMessage: response,
|
||||
Padding: make([]byte, int(paddingBytes)),
|
||||
}
|
||||
return &ObliviousDNSResponse{
|
||||
msg,
|
||||
}
|
||||
}
|
||||
|
||||
func UnmarshalResponseBody(data []byte) (*ObliviousDNSResponse, error) {
|
||||
msg, err := UnmarshalMessageBody(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ObliviousDNSResponse{msg}, nil
|
||||
}
|
||||
|
||||
//
|
||||
// struct {
|
||||
// uint8 message_type;
|
||||
// opaque key_id<0..2^16-1>;
|
||||
// opaque encrypted_message<1..2^16-1>;
|
||||
// } ObliviousDoHMessage;
|
||||
//
|
||||
type ObliviousDNSMessage struct {
|
||||
MessageType ObliviousMessageType
|
||||
KeyID []byte
|
||||
EncryptedMessage []byte
|
||||
}
|
||||
|
||||
func (m ObliviousDNSMessage) Type() ObliviousMessageType {
|
||||
return m.MessageType
|
||||
}
|
||||
|
||||
func CreateObliviousDNSMessage(messageType ObliviousMessageType, keyID []byte, encryptedMessage []byte) *ObliviousDNSMessage {
|
||||
return &ObliviousDNSMessage{
|
||||
MessageType: messageType,
|
||||
KeyID: keyID,
|
||||
EncryptedMessage: encryptedMessage,
|
||||
}
|
||||
}
|
||||
|
||||
func (m ObliviousDNSMessage) Marshal() []byte {
|
||||
encodedKey := encodeLengthPrefixedSlice(m.KeyID)
|
||||
encodedMessage := encodeLengthPrefixedSlice(m.EncryptedMessage)
|
||||
|
||||
result := append([]byte{uint8(m.MessageType)}, encodedKey...)
|
||||
result = append(result, encodedMessage...)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func UnmarshalDNSMessage(data []byte) (ObliviousDNSMessage, error) {
|
||||
if len(data) < 1 {
|
||||
return ObliviousDNSMessage{}, fmt.Errorf("Invalid data length: %d", len(data))
|
||||
}
|
||||
|
||||
messageType := data[0]
|
||||
keyID, messageOffset, err := decodeLengthPrefixedSlice(data[1:])
|
||||
if err != nil {
|
||||
return ObliviousDNSMessage{}, err
|
||||
}
|
||||
encryptedMessage, _, err := decodeLengthPrefixedSlice(data[1+messageOffset:])
|
||||
if err != nil {
|
||||
return ObliviousDNSMessage{}, err
|
||||
}
|
||||
|
||||
return ObliviousDNSMessage{
|
||||
MessageType: ObliviousMessageType(messageType),
|
||||
KeyID: keyID,
|
||||
EncryptedMessage: encryptedMessage,
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,564 @@
|
|||
// The MIT License
|
||||
//
|
||||
// Copyright (c) 2019-2020, Cloudflare, Inc. and Apple, Inc. 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.
|
||||
|
||||
package odoh
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/cisco/go-hpke"
|
||||
)
|
||||
|
||||
const (
|
||||
ODOH_VERSION = uint16(0xff03)
|
||||
ODOH_SECRET_LENGTH = 32
|
||||
ODOH_PADDING_BYTE = uint8(0)
|
||||
ODOH_LABEL_KEY_ID = "odoh key id"
|
||||
ODOH_LABEL_KEY = "odoh key"
|
||||
ODOH_LABEL_NONCE = "odoh nonce"
|
||||
ODOH_LABEL_SECRET = "odoh secret"
|
||||
ODOH_LABEL_QUERY = "odoh query"
|
||||
ODOH_DEFAULT_KEMID hpke.KEMID = hpke.DHKEM_X25519
|
||||
ODOH_DEFAULT_KDFID hpke.KDFID = hpke.KDF_HKDF_SHA256
|
||||
ODOH_DEFAULT_AEADID hpke.AEADID = hpke.AEAD_AESGCM128
|
||||
)
|
||||
|
||||
type ObliviousDoHConfigContents struct {
|
||||
KemID hpke.KEMID
|
||||
KdfID hpke.KDFID
|
||||
AeadID hpke.AEADID
|
||||
PublicKeyBytes []byte
|
||||
}
|
||||
|
||||
func CreateObliviousDoHConfigContents(kemID hpke.KEMID, kdfID hpke.KDFID, aeadID hpke.AEADID, publicKeyBytes []byte) (ObliviousDoHConfigContents, error) {
|
||||
suite, err := hpke.AssembleCipherSuite(kemID, kdfID, aeadID)
|
||||
if err != nil {
|
||||
return ObliviousDoHConfigContents{}, err
|
||||
}
|
||||
|
||||
_, err = suite.KEM.Deserialize(publicKeyBytes)
|
||||
if err != nil {
|
||||
return ObliviousDoHConfigContents{}, err
|
||||
}
|
||||
|
||||
return ObliviousDoHConfigContents{
|
||||
KemID: kemID,
|
||||
KdfID: kdfID,
|
||||
AeadID: aeadID,
|
||||
PublicKeyBytes: publicKeyBytes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (k ObliviousDoHConfigContents) KeyID() []byte {
|
||||
suite, err := hpke.AssembleCipherSuite(k.KemID, k.KdfID, k.AeadID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
identifiers := make([]byte, 8)
|
||||
binary.BigEndian.PutUint16(identifiers[0:], uint16(k.KemID))
|
||||
binary.BigEndian.PutUint16(identifiers[2:], uint16(k.KdfID))
|
||||
binary.BigEndian.PutUint16(identifiers[4:], uint16(k.AeadID))
|
||||
binary.BigEndian.PutUint16(identifiers[6:], uint16(len(k.PublicKeyBytes)))
|
||||
config := append(identifiers, k.PublicKeyBytes...)
|
||||
|
||||
prk := suite.KDF.Extract(nil, config)
|
||||
identifier := suite.KDF.Expand(prk, []byte(ODOH_LABEL_KEY_ID), suite.KDF.OutputSize())
|
||||
|
||||
return identifier
|
||||
}
|
||||
|
||||
func (k ObliviousDoHConfigContents) Marshal() []byte {
|
||||
identifiers := make([]byte, 8)
|
||||
binary.BigEndian.PutUint16(identifiers[0:], uint16(k.KemID))
|
||||
binary.BigEndian.PutUint16(identifiers[2:], uint16(k.KdfID))
|
||||
binary.BigEndian.PutUint16(identifiers[4:], uint16(k.AeadID))
|
||||
binary.BigEndian.PutUint16(identifiers[6:], uint16(len(k.PublicKeyBytes)))
|
||||
|
||||
response := append(identifiers, k.PublicKeyBytes...)
|
||||
return response
|
||||
}
|
||||
|
||||
func UnmarshalObliviousDoHConfigContents(buffer []byte) (ObliviousDoHConfigContents, error) {
|
||||
if len(buffer) < 8 {
|
||||
return ObliviousDoHConfigContents{}, errors.New("Invalid serialized ObliviousDoHConfigContents")
|
||||
}
|
||||
|
||||
kemId := binary.BigEndian.Uint16(buffer[0:])
|
||||
kdfId := binary.BigEndian.Uint16(buffer[2:])
|
||||
aeadId := binary.BigEndian.Uint16(buffer[4:])
|
||||
publicKeyLength := binary.BigEndian.Uint16(buffer[6:])
|
||||
|
||||
if len(buffer[8:]) < int(publicKeyLength) {
|
||||
return ObliviousDoHConfigContents{}, errors.New("Invalid serialized ObliviousDoHConfigContents")
|
||||
}
|
||||
|
||||
publicKeyBytes := buffer[8 : 8+publicKeyLength]
|
||||
|
||||
var KemID hpke.KEMID
|
||||
var KdfID hpke.KDFID
|
||||
var AeadID hpke.AEADID
|
||||
|
||||
switch kemId {
|
||||
case 0x0010:
|
||||
KemID = hpke.DHKEM_P256
|
||||
break
|
||||
case 0x0012:
|
||||
KemID = hpke.DHKEM_P521
|
||||
break
|
||||
case 0x0020:
|
||||
KemID = hpke.DHKEM_X25519
|
||||
break
|
||||
case 0x0021:
|
||||
KemID = hpke.DHKEM_X448
|
||||
break
|
||||
case 0xFFFE:
|
||||
KemID = hpke.KEM_SIKE503
|
||||
break
|
||||
case 0xFFFF:
|
||||
KemID = hpke.KEM_SIKE751
|
||||
break
|
||||
default:
|
||||
return ObliviousDoHConfigContents{}, errors.New(fmt.Sprintf("Unsupported KEMID: %04x", kemId))
|
||||
}
|
||||
|
||||
switch kdfId {
|
||||
case 0x0001:
|
||||
KdfID = hpke.KDF_HKDF_SHA256
|
||||
break
|
||||
case 0x0002:
|
||||
KdfID = hpke.KDF_HKDF_SHA384
|
||||
break
|
||||
case 0x0003:
|
||||
KdfID = hpke.KDF_HKDF_SHA512
|
||||
break
|
||||
default:
|
||||
return ObliviousDoHConfigContents{}, errors.New(fmt.Sprintf("Unsupported KDFID: %04x", kdfId))
|
||||
}
|
||||
|
||||
switch aeadId {
|
||||
case 0x0001:
|
||||
AeadID = hpke.AEAD_AESGCM128
|
||||
break
|
||||
case 0x0002:
|
||||
AeadID = hpke.AEAD_AESGCM256
|
||||
break
|
||||
case 0x0003:
|
||||
AeadID = hpke.AEAD_CHACHA20POLY1305
|
||||
break
|
||||
default:
|
||||
return ObliviousDoHConfigContents{}, errors.New(fmt.Sprintf("Unsupported AEADID: %04x", aeadId))
|
||||
}
|
||||
|
||||
suite, err := hpke.AssembleCipherSuite(KemID, KdfID, AeadID)
|
||||
if err != nil {
|
||||
return ObliviousDoHConfigContents{}, errors.New(fmt.Sprintf("Unsupported HPKE ciphersuite"))
|
||||
}
|
||||
|
||||
_, err = suite.KEM.Deserialize(publicKeyBytes)
|
||||
if err != nil {
|
||||
return ObliviousDoHConfigContents{}, errors.New(fmt.Sprintf("Invalid HPKE public key bytes"))
|
||||
}
|
||||
|
||||
return ObliviousDoHConfigContents{
|
||||
KemID: KemID,
|
||||
KdfID: KdfID,
|
||||
AeadID: AeadID,
|
||||
PublicKeyBytes: publicKeyBytes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (k ObliviousDoHConfigContents) PublicKey() []byte {
|
||||
return k.PublicKeyBytes
|
||||
}
|
||||
|
||||
func (k ObliviousDoHConfigContents) CipherSuite() (hpke.CipherSuite, error) {
|
||||
return hpke.AssembleCipherSuite(k.KemID, k.KdfID, k.AeadID)
|
||||
}
|
||||
|
||||
type ObliviousDoHConfig struct {
|
||||
Version uint16
|
||||
Contents ObliviousDoHConfigContents
|
||||
}
|
||||
|
||||
func CreateObliviousDoHConfig(contents ObliviousDoHConfigContents) ObliviousDoHConfig {
|
||||
return ObliviousDoHConfig{
|
||||
Version: ODOH_VERSION,
|
||||
Contents: contents,
|
||||
}
|
||||
}
|
||||
|
||||
func (c ObliviousDoHConfig) Marshal() []byte {
|
||||
marshalledConfig := c.Contents.Marshal()
|
||||
|
||||
buffer := make([]byte, 4)
|
||||
binary.BigEndian.PutUint16(buffer[0:], uint16(c.Version))
|
||||
binary.BigEndian.PutUint16(buffer[2:], uint16(len(marshalledConfig)))
|
||||
|
||||
configBytes := append(buffer, marshalledConfig...)
|
||||
return configBytes
|
||||
}
|
||||
|
||||
func parseConfigHeader(buffer []byte) (uint16, uint16, error) {
|
||||
if len(buffer) < 4 {
|
||||
return uint16(0), uint16(0), errors.New("Invalid ObliviousDoHConfig encoding")
|
||||
}
|
||||
|
||||
version := binary.BigEndian.Uint16(buffer[0:])
|
||||
length := binary.BigEndian.Uint16(buffer[2:])
|
||||
return version, length, nil
|
||||
}
|
||||
|
||||
func isSupportedConfigVersion(version uint16) bool {
|
||||
return version == ODOH_VERSION
|
||||
}
|
||||
|
||||
func UnmarshalObliviousDoHConfig(buffer []byte) (ObliviousDoHConfig, error) {
|
||||
version, length, err := parseConfigHeader(buffer)
|
||||
if err != nil {
|
||||
return ObliviousDoHConfig{}, err
|
||||
}
|
||||
|
||||
if !isSupportedConfigVersion(version) {
|
||||
return ObliviousDoHConfig{}, errors.New(fmt.Sprintf("Unsupported version: %04x", version))
|
||||
}
|
||||
if len(buffer[4:]) < int(length) {
|
||||
return ObliviousDoHConfig{}, errors.New(fmt.Sprintf("Invalid serialized ObliviousDoHConfig, expected %v bytes, got %v", length, len(buffer[4:])))
|
||||
}
|
||||
|
||||
configContents, err := UnmarshalObliviousDoHConfigContents(buffer[4:])
|
||||
if err != nil {
|
||||
return ObliviousDoHConfig{}, err
|
||||
}
|
||||
|
||||
return ObliviousDoHConfig{
|
||||
Version: version,
|
||||
Contents: configContents,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ObliviousDoHConfigs struct {
|
||||
Configs []ObliviousDoHConfig
|
||||
}
|
||||
|
||||
func CreateObliviousDoHConfigs(configs []ObliviousDoHConfig) ObliviousDoHConfigs {
|
||||
return ObliviousDoHConfigs{
|
||||
Configs: configs,
|
||||
}
|
||||
}
|
||||
|
||||
func (c ObliviousDoHConfigs) Marshal() []byte {
|
||||
serializedConfigs := make([]byte, 0)
|
||||
for _, config := range c.Configs {
|
||||
serializedConfigs = append(serializedConfigs, config.Marshal()...)
|
||||
}
|
||||
|
||||
buffer := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(buffer[0:], uint16(len(serializedConfigs)))
|
||||
|
||||
result := append(buffer, serializedConfigs...)
|
||||
return result
|
||||
}
|
||||
|
||||
func UnmarshalObliviousDoHConfigs(buffer []byte) (ObliviousDoHConfigs, error) {
|
||||
if len(buffer) < 2 {
|
||||
return ObliviousDoHConfigs{}, errors.New("Invalid ObliviousDoHConfigs encoding")
|
||||
}
|
||||
|
||||
configs := make([]ObliviousDoHConfig, 0)
|
||||
length := binary.BigEndian.Uint16(buffer[0:])
|
||||
offset := uint16(2)
|
||||
|
||||
for {
|
||||
configVersion, configLength, err := parseConfigHeader(buffer[offset:])
|
||||
if err != nil {
|
||||
return ObliviousDoHConfigs{}, errors.New("Invalid ObliviousDoHConfigs encoding")
|
||||
}
|
||||
|
||||
if uint16(len(buffer[offset:])) < configLength {
|
||||
// The configs vector is encoded incorrectly, so discard the whole thing
|
||||
return ObliviousDoHConfigs{}, errors.New(fmt.Sprintf("Invalid serialized ObliviousDoHConfig, expected %v bytes, got %v", length, len(buffer[offset:])))
|
||||
}
|
||||
|
||||
if isSupportedConfigVersion(configVersion) {
|
||||
config, err := UnmarshalObliviousDoHConfig(buffer[offset:])
|
||||
if err == nil {
|
||||
configs = append(configs, config)
|
||||
}
|
||||
} else {
|
||||
// Skip over unsupported versions
|
||||
}
|
||||
|
||||
offset += 4 + configLength
|
||||
if offset >= 2+length {
|
||||
// Stop reading
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return CreateObliviousDoHConfigs(configs), nil
|
||||
}
|
||||
|
||||
type ObliviousDoHKeyPair struct {
|
||||
Config ObliviousDoHConfig
|
||||
secretKey hpke.KEMPrivateKey
|
||||
Seed []byte
|
||||
}
|
||||
|
||||
func CreateKeyPairFromSeed(kemID hpke.KEMID, kdfID hpke.KDFID, aeadID hpke.AEADID, ikm []byte) (ObliviousDoHKeyPair, error) {
|
||||
suite, err := hpke.AssembleCipherSuite(kemID, kdfID, aeadID)
|
||||
if err != nil {
|
||||
return ObliviousDoHKeyPair{}, err
|
||||
}
|
||||
|
||||
sk, pk, err := suite.KEM.DeriveKeyPair(ikm)
|
||||
if err != nil {
|
||||
return ObliviousDoHKeyPair{}, err
|
||||
}
|
||||
|
||||
configContents, err := CreateObliviousDoHConfigContents(kemID, kdfID, aeadID, suite.KEM.Serialize(pk))
|
||||
if err != nil {
|
||||
return ObliviousDoHKeyPair{}, err
|
||||
}
|
||||
|
||||
config := CreateObliviousDoHConfig(configContents)
|
||||
|
||||
return ObliviousDoHKeyPair{
|
||||
Config: config,
|
||||
secretKey: sk,
|
||||
Seed: ikm,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func CreateDefaultKeyPairFromSeed(seed []byte) (ObliviousDoHKeyPair, error) {
|
||||
return CreateKeyPairFromSeed(ODOH_DEFAULT_KEMID, ODOH_DEFAULT_KDFID, ODOH_DEFAULT_AEADID, seed)
|
||||
}
|
||||
|
||||
func CreateKeyPair(kemID hpke.KEMID, kdfID hpke.KDFID, aeadID hpke.AEADID) (ObliviousDoHKeyPair, error) {
|
||||
suite, err := hpke.AssembleCipherSuite(kemID, kdfID, aeadID)
|
||||
if err != nil {
|
||||
return ObliviousDoHKeyPair{}, err
|
||||
}
|
||||
|
||||
ikm := make([]byte, suite.KEM.PrivateKeySize())
|
||||
rand.Reader.Read(ikm)
|
||||
sk, pk, err := suite.KEM.DeriveKeyPair(ikm)
|
||||
if err != nil {
|
||||
return ObliviousDoHKeyPair{}, err
|
||||
}
|
||||
|
||||
configContents, err := CreateObliviousDoHConfigContents(kemID, kdfID, aeadID, suite.KEM.Serialize(pk))
|
||||
if err != nil {
|
||||
return ObliviousDoHKeyPair{}, err
|
||||
}
|
||||
|
||||
config := CreateObliviousDoHConfig(configContents)
|
||||
|
||||
return ObliviousDoHKeyPair{
|
||||
Config: config,
|
||||
secretKey: sk,
|
||||
Seed: ikm,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func CreateDefaultKeyPair() (ObliviousDoHKeyPair, error) {
|
||||
return CreateKeyPair(ODOH_DEFAULT_KEMID, ODOH_DEFAULT_KDFID, ODOH_DEFAULT_AEADID)
|
||||
}
|
||||
|
||||
type QueryContext struct {
|
||||
odohSecret []byte
|
||||
suite hpke.CipherSuite
|
||||
query []byte
|
||||
publicKey ObliviousDoHConfigContents
|
||||
}
|
||||
|
||||
func (c QueryContext) DecryptResponse(message ObliviousDNSMessage) ([]byte, error) {
|
||||
aad := append([]byte{byte(ResponseType)}, []byte{0x00, 0x00}...) // 0-length encoded KeyID
|
||||
|
||||
odohPRK := c.suite.KDF.Extract(c.query, c.odohSecret)
|
||||
key := c.suite.KDF.Expand(odohPRK, []byte(ODOH_LABEL_KEY), c.suite.AEAD.KeySize())
|
||||
nonce := c.suite.KDF.Expand(odohPRK, []byte(ODOH_LABEL_NONCE), c.suite.AEAD.NonceSize())
|
||||
|
||||
aead, err := c.suite.AEAD.New(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return aead.Open(nil, nonce, message.EncryptedMessage, aad)
|
||||
}
|
||||
|
||||
type ResponseContext struct {
|
||||
query []byte
|
||||
suite hpke.CipherSuite
|
||||
odohSecret []byte
|
||||
}
|
||||
|
||||
func (c ResponseContext) EncryptResponse(response *ObliviousDNSResponse) (ObliviousDNSMessage, error) {
|
||||
aad := append([]byte{byte(ResponseType)}, []byte{0x00, 0x00}...) // 0-length encoded KeyID
|
||||
|
||||
odohPRK := c.suite.KDF.Extract(c.query, c.odohSecret)
|
||||
key := c.suite.KDF.Expand(odohPRK, []byte(ODOH_LABEL_KEY), c.suite.AEAD.KeySize())
|
||||
nonce := c.suite.KDF.Expand(odohPRK, []byte(ODOH_LABEL_NONCE), c.suite.AEAD.NonceSize())
|
||||
|
||||
aead, err := c.suite.AEAD.New(key)
|
||||
if err != nil {
|
||||
return ObliviousDNSMessage{}, err
|
||||
}
|
||||
|
||||
ciphertext := aead.Seal(nil, nonce, response.Marshal(), aad)
|
||||
|
||||
odohMessage := ObliviousDNSMessage{
|
||||
KeyID: nil,
|
||||
MessageType: ResponseType,
|
||||
EncryptedMessage: ciphertext,
|
||||
}
|
||||
|
||||
return odohMessage, nil
|
||||
}
|
||||
|
||||
func (targetKey ObliviousDoHConfigContents) EncryptQuery(query *ObliviousDNSQuery) (ObliviousDNSMessage, QueryContext, error) {
|
||||
suite, err := hpke.AssembleCipherSuite(targetKey.KemID, targetKey.KdfID, targetKey.AeadID)
|
||||
if err != nil {
|
||||
return ObliviousDNSMessage{}, QueryContext{}, err
|
||||
}
|
||||
|
||||
pkR, err := suite.KEM.Deserialize(targetKey.PublicKeyBytes)
|
||||
if err != nil {
|
||||
return ObliviousDNSMessage{}, QueryContext{}, err
|
||||
}
|
||||
|
||||
enc, ctxI, err := hpke.SetupBaseS(suite, rand.Reader, pkR, []byte(ODOH_LABEL_QUERY))
|
||||
if err != nil {
|
||||
return ObliviousDNSMessage{}, QueryContext{}, err
|
||||
}
|
||||
|
||||
keyID := targetKey.KeyID()
|
||||
keyIDLength := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(keyIDLength, uint16(len(keyID)))
|
||||
aad := append([]byte{byte(QueryType)}, keyIDLength...)
|
||||
aad = append(aad, keyID...)
|
||||
|
||||
encodedMessage := query.Marshal()
|
||||
ct := ctxI.Seal(aad, encodedMessage)
|
||||
odohSecret := ctxI.Export([]byte(ODOH_LABEL_SECRET), ODOH_SECRET_LENGTH)
|
||||
|
||||
return ObliviousDNSMessage{
|
||||
KeyID: targetKey.KeyID(),
|
||||
MessageType: QueryType,
|
||||
EncryptedMessage: append(enc, ct...),
|
||||
}, QueryContext{
|
||||
odohSecret: odohSecret,
|
||||
suite: suite,
|
||||
query: query.Marshal(),
|
||||
publicKey: targetKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func validateMessagePadding(padding []byte) bool {
|
||||
validPadding := 1
|
||||
for _, v := range padding {
|
||||
validPadding &= subtle.ConstantTimeByteEq(v, ODOH_PADDING_BYTE)
|
||||
}
|
||||
return validPadding == 1
|
||||
}
|
||||
|
||||
func (privateKey ObliviousDoHKeyPair) DecryptQuery(message ObliviousDNSMessage) (*ObliviousDNSQuery, ResponseContext, error) {
|
||||
if message.MessageType != QueryType {
|
||||
return nil, ResponseContext{}, errors.New("message is not a query")
|
||||
}
|
||||
|
||||
suite, err := hpke.AssembleCipherSuite(privateKey.Config.Contents.KemID, privateKey.Config.Contents.KdfID, privateKey.Config.Contents.AeadID)
|
||||
if err != nil {
|
||||
return nil, ResponseContext{}, err
|
||||
}
|
||||
|
||||
keySize := suite.KEM.PublicKeySize()
|
||||
enc := message.EncryptedMessage[0:keySize]
|
||||
ct := message.EncryptedMessage[keySize:]
|
||||
|
||||
ctxR, err := hpke.SetupBaseR(suite, privateKey.secretKey, enc, []byte(ODOH_LABEL_QUERY))
|
||||
if err != nil {
|
||||
return nil, ResponseContext{}, err
|
||||
}
|
||||
|
||||
odohSecret := ctxR.Export([]byte(ODOH_LABEL_SECRET), ODOH_SECRET_LENGTH)
|
||||
|
||||
keyID := privateKey.Config.Contents.KeyID()
|
||||
keyIDLength := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(keyIDLength, uint16(len(keyID)))
|
||||
aad := append([]byte{byte(QueryType)}, keyIDLength...)
|
||||
aad = append(aad, keyID...)
|
||||
|
||||
dnsMessage, err := ctxR.Open(aad, ct)
|
||||
if err != nil {
|
||||
return nil, ResponseContext{}, err
|
||||
}
|
||||
|
||||
query, err := UnmarshalQueryBody(dnsMessage)
|
||||
if err != nil {
|
||||
return nil, ResponseContext{}, err
|
||||
}
|
||||
|
||||
if !validateMessagePadding(query.Padding) {
|
||||
return nil, ResponseContext{}, errors.New("invalid padding")
|
||||
}
|
||||
|
||||
responseContext := ResponseContext{
|
||||
odohSecret: odohSecret,
|
||||
suite: suite,
|
||||
query: query.Marshal(),
|
||||
}
|
||||
|
||||
return query, responseContext, nil
|
||||
}
|
||||
|
||||
func SealQuery(dnsQuery []byte, publicKey ObliviousDoHConfigContents) (ObliviousDNSMessage, QueryContext, error) {
|
||||
odohQuery := CreateObliviousDNSQuery(dnsQuery, 0)
|
||||
|
||||
odohMessage, queryContext, err := publicKey.EncryptQuery(odohQuery)
|
||||
if err != nil {
|
||||
return ObliviousDNSMessage{}, QueryContext{}, err
|
||||
}
|
||||
|
||||
return odohMessage, queryContext, nil
|
||||
}
|
||||
|
||||
func (c QueryContext) OpenAnswer(message ObliviousDNSMessage) ([]byte, error) {
|
||||
if message.MessageType != ResponseType {
|
||||
return nil, errors.New("message is not a response")
|
||||
}
|
||||
|
||||
decryptedResponseBytes, err := c.DecryptResponse(message)
|
||||
if err != nil {
|
||||
return nil, errors.New("unable to decrypt the obtained response using the symmetric key sent")
|
||||
}
|
||||
|
||||
decryptedResponse, err := UnmarshalResponseBody(decryptedResponseBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decryptedResponse.DnsMessage, nil
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -26,7 +26,6 @@ avoiding breaking changes wherever reasonable. We support the last two versions
|
|||
A not-so-up-to-date-list-that-may-be-actually-current:
|
||||
|
||||
* https://github.com/coredns/coredns
|
||||
* https://cloudflare.com
|
||||
* https://github.com/abh/geodns
|
||||
* https://github.com/baidu/bfe
|
||||
* http://www.statdns.com/
|
||||
|
@ -42,11 +41,9 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
|||
* https://github.com/StalkR/dns-reverse-proxy
|
||||
* https://github.com/tianon/rawdns
|
||||
* https://mesosphere.github.io/mesos-dns/
|
||||
* https://pulse.turbobytes.com/
|
||||
* https://github.com/fcambus/statzone
|
||||
* https://github.com/benschw/dns-clb-go
|
||||
* https://github.com/corny/dnscheck for <http://public-dns.info/>
|
||||
* https://namesmith.io
|
||||
* https://github.com/miekg/unbound
|
||||
* https://github.com/miekg/exdns
|
||||
* https://dnslookup.org
|
||||
|
@ -55,24 +52,22 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
|||
* https://github.com/mehrdadrad/mylg
|
||||
* https://github.com/bamarni/dockness
|
||||
* https://github.com/fffaraz/microdns
|
||||
* http://kelda.io
|
||||
* https://github.com/ipdcode/hades <https://jd.com>
|
||||
* https://github.com/StackExchange/dnscontrol/
|
||||
* https://www.dnsperf.com/
|
||||
* https://dnssectest.net/
|
||||
* https://dns.apebits.com
|
||||
* https://github.com/oif/apex
|
||||
* https://github.com/jedisct1/dnscrypt-proxy
|
||||
* https://github.com/jedisct1/rpdns
|
||||
* https://github.com/xor-gate/sshfp
|
||||
* https://github.com/rs/dnstrace
|
||||
* https://blitiri.com.ar/p/dnss ([github mirror](https://github.com/albertito/dnss))
|
||||
* https://github.com/semihalev/sdns
|
||||
* https://render.com
|
||||
* https://github.com/peterzen/goresolver
|
||||
* https://github.com/folbricht/routedns
|
||||
* https://domainr.com/
|
||||
* https://zonedb.org/
|
||||
* https://router7.org/
|
||||
|
||||
Send pull request if you want to be listed here.
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ type Client struct {
|
|||
Dialer *net.Dialer // a net.Dialer used to set local address, timeouts and more
|
||||
// Timeout is a cumulative timeout for dial, write and read, defaults to 0 (disabled) - overrides DialTimeout, ReadTimeout,
|
||||
// WriteTimeout when non-zero. Can be overridden with net.Dialer.Timeout (see Client.ExchangeWithDialer and
|
||||
// Client.Dialer) or context.Context.Deadline (see the deprecated ExchangeContext)
|
||||
// Client.Dialer) or context.Context.Deadline (see ExchangeContext)
|
||||
Timeout time.Duration
|
||||
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds, or net.Dialer.Timeout if expiring earlier - overridden by Timeout when that value is non-zero
|
||||
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
|
||||
|
@ -106,7 +106,7 @@ func (c *Client) Dial(address string) (conn *Conn, err error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn.UDPSize = c.UDPSize
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -612,6 +613,65 @@ func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
|
|||
return off, nil
|
||||
}
|
||||
|
||||
func unpackDataSVCB(msg []byte, off int) ([]SVCBKeyValue, int, error) {
|
||||
var xs []SVCBKeyValue
|
||||
var code uint16
|
||||
var length uint16
|
||||
var err error
|
||||
for off < len(msg) {
|
||||
code, off, err = unpackUint16(msg, off)
|
||||
if err != nil {
|
||||
return nil, len(msg), &Error{err: "overflow unpacking SVCB"}
|
||||
}
|
||||
length, off, err = unpackUint16(msg, off)
|
||||
if err != nil || off+int(length) > len(msg) {
|
||||
return nil, len(msg), &Error{err: "overflow unpacking SVCB"}
|
||||
}
|
||||
e := makeSVCBKeyValue(SVCBKey(code))
|
||||
if e == nil {
|
||||
return nil, len(msg), &Error{err: "bad SVCB key"}
|
||||
}
|
||||
if err := e.unpack(msg[off : off+int(length)]); err != nil {
|
||||
return nil, len(msg), err
|
||||
}
|
||||
if len(xs) > 0 && e.Key() <= xs[len(xs)-1].Key() {
|
||||
return nil, len(msg), &Error{err: "SVCB keys not in strictly increasing order"}
|
||||
}
|
||||
xs = append(xs, e)
|
||||
off += int(length)
|
||||
}
|
||||
return xs, off, nil
|
||||
}
|
||||
|
||||
func packDataSVCB(pairs []SVCBKeyValue, msg []byte, off int) (int, error) {
|
||||
pairs = append([]SVCBKeyValue(nil), pairs...)
|
||||
sort.Slice(pairs, func(i, j int) bool {
|
||||
return pairs[i].Key() < pairs[j].Key()
|
||||
})
|
||||
prev := svcb_RESERVED
|
||||
for _, el := range pairs {
|
||||
if el.Key() == prev {
|
||||
return len(msg), &Error{err: "repeated SVCB keys are not allowed"}
|
||||
}
|
||||
prev = el.Key()
|
||||
packed, err := el.pack()
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
}
|
||||
off, err = packUint16(uint16(el.Key()), msg, off)
|
||||
if err != nil {
|
||||
return len(msg), &Error{err: "overflow packing SVCB"}
|
||||
}
|
||||
off, err = packUint16(uint16(len(packed)), msg, off)
|
||||
if err != nil || off+len(packed) > len(msg) {
|
||||
return len(msg), &Error{err: "overflow packing SVCB"}
|
||||
}
|
||||
copy(msg[off:off+len(packed)], packed)
|
||||
off += len(packed)
|
||||
}
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func unpackDataDomainNames(msg []byte, off, end int) ([]string, int, error) {
|
||||
var (
|
||||
servers []string
|
||||
|
@ -683,6 +743,13 @@ func packDataAplPrefix(p *APLPrefix, msg []byte, off int) (int, error) {
|
|||
if p.Negation {
|
||||
n = 0x80
|
||||
}
|
||||
|
||||
// trim trailing zero bytes as specified in RFC3123 Sections 4.1 and 4.2.
|
||||
i := len(addr) - 1
|
||||
for ; i >= 0 && addr[i] == 0; i-- {
|
||||
}
|
||||
addr = addr[:i+1]
|
||||
|
||||
adflen := uint8(len(addr)) & 0x7f
|
||||
off, err = packUint8(n|adflen, msg, off)
|
||||
if err != nil {
|
||||
|
|
|
@ -1210,11 +1210,29 @@ func stringToCm(token string) (e, m uint8, ok bool) {
|
|||
if cmeters, err = strconv.Atoi(s[1]); err != nil {
|
||||
return
|
||||
}
|
||||
// There's no point in having more than 2 digits in this part, and would rather make the implementation complicated ('123' should be treated as '12').
|
||||
// So we simply reject it.
|
||||
// We also make sure the first character is a digit to reject '+-' signs.
|
||||
if len(s[1]) > 2 || s[1][0] < '0' || s[1][0] > '9' {
|
||||
return
|
||||
}
|
||||
if len(s[1]) == 1 {
|
||||
// 'nn.1' must be treated as 'nn-meters and 10cm, not 1cm.
|
||||
cmeters *= 10
|
||||
}
|
||||
if len(s[0]) == 0 {
|
||||
// This will allow omitting the 'meter' part, like .01 (meaning 0.01m = 1cm).
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case 1:
|
||||
if meters, err = strconv.Atoi(s[0]); err != nil {
|
||||
return
|
||||
}
|
||||
// RFC1876 states the max value is 90000000.00. The latter two conditions enforce it.
|
||||
if s[0][0] < '0' || s[0][0] > '9' || meters > 90000000 || (meters == 90000000 && cmeters != 0) {
|
||||
return
|
||||
}
|
||||
case 0:
|
||||
// huh?
|
||||
return 0, 0, false
|
||||
|
@ -1227,13 +1245,10 @@ func stringToCm(token string) (e, m uint8, ok bool) {
|
|||
e = 0
|
||||
val = cmeters
|
||||
}
|
||||
for val > 10 {
|
||||
for val >= 10 {
|
||||
e++
|
||||
val /= 10
|
||||
}
|
||||
if e > 9 {
|
||||
ok = false
|
||||
}
|
||||
m = uint8(val)
|
||||
return
|
||||
}
|
||||
|
@ -1275,6 +1290,9 @@ func appendOrigin(name, origin string) string {
|
|||
|
||||
// LOC record helper function
|
||||
func locCheckNorth(token string, latitude uint32) (uint32, bool) {
|
||||
if latitude > 90 * 1000 * 60 * 60 {
|
||||
return latitude, false
|
||||
}
|
||||
switch token {
|
||||
case "n", "N":
|
||||
return LOC_EQUATOR + latitude, true
|
||||
|
@ -1286,6 +1304,9 @@ func locCheckNorth(token string, latitude uint32) (uint32, bool) {
|
|||
|
||||
// LOC record helper function
|
||||
func locCheckEast(token string, longitude uint32) (uint32, bool) {
|
||||
if longitude > 180 * 1000 * 60 * 60 {
|
||||
return longitude, false
|
||||
}
|
||||
switch token {
|
||||
case "e", "E":
|
||||
return LOC_EQUATOR + longitude, true
|
||||
|
|
|
@ -590,7 +590,7 @@ func (rr *LOC) parse(c *zlexer, o string) *ParseError {
|
|||
// North
|
||||
l, _ := c.Next()
|
||||
i, e := strconv.ParseUint(l.token, 10, 32)
|
||||
if e != nil || l.err {
|
||||
if e != nil || l.err || i > 90 {
|
||||
return &ParseError{"", "bad LOC Latitude", l}
|
||||
}
|
||||
rr.Latitude = 1000 * 60 * 60 * uint32(i)
|
||||
|
@ -601,7 +601,7 @@ func (rr *LOC) parse(c *zlexer, o string) *ParseError {
|
|||
if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
|
||||
goto East
|
||||
}
|
||||
if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err {
|
||||
if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 59 {
|
||||
return &ParseError{"", "bad LOC Latitude minutes", l}
|
||||
} else {
|
||||
rr.Latitude += 1000 * 60 * uint32(i)
|
||||
|
@ -609,7 +609,7 @@ func (rr *LOC) parse(c *zlexer, o string) *ParseError {
|
|||
|
||||
c.Next() // zBlank
|
||||
l, _ = c.Next()
|
||||
if i, err := strconv.ParseFloat(l.token, 32); err != nil || l.err {
|
||||
if i, err := strconv.ParseFloat(l.token, 32); err != nil || l.err || i < 0 || i >= 60 {
|
||||
return &ParseError{"", "bad LOC Latitude seconds", l}
|
||||
} else {
|
||||
rr.Latitude += uint32(1000 * i)
|
||||
|
@ -627,7 +627,7 @@ East:
|
|||
// East
|
||||
c.Next() // zBlank
|
||||
l, _ = c.Next()
|
||||
if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err {
|
||||
if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 180 {
|
||||
return &ParseError{"", "bad LOC Longitude", l}
|
||||
} else {
|
||||
rr.Longitude = 1000 * 60 * 60 * uint32(i)
|
||||
|
@ -638,14 +638,14 @@ East:
|
|||
if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
|
||||
goto Altitude
|
||||
}
|
||||
if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err {
|
||||
if i, err := strconv.ParseUint(l.token, 10, 32); err != nil || l.err || i > 59 {
|
||||
return &ParseError{"", "bad LOC Longitude minutes", l}
|
||||
} else {
|
||||
rr.Longitude += 1000 * 60 * uint32(i)
|
||||
}
|
||||
c.Next() // zBlank
|
||||
l, _ = c.Next()
|
||||
if i, err := strconv.ParseFloat(l.token, 32); err != nil || l.err {
|
||||
if i, err := strconv.ParseFloat(l.token, 32); err != nil || l.err || i < 0 || i >= 60 {
|
||||
return &ParseError{"", "bad LOC Longitude seconds", l}
|
||||
} else {
|
||||
rr.Longitude += uint32(1000 * i)
|
||||
|
@ -668,7 +668,7 @@ Altitude:
|
|||
if l.token[len(l.token)-1] == 'M' || l.token[len(l.token)-1] == 'm' {
|
||||
l.token = l.token[0 : len(l.token)-1]
|
||||
}
|
||||
if i, err := strconv.ParseFloat(l.token, 32); err != nil {
|
||||
if i, err := strconv.ParseFloat(l.token, 64); err != nil {
|
||||
return &ParseError{"", "bad LOC Altitude", l}
|
||||
} else {
|
||||
rr.Altitude = uint32(i*100.0 + 10000000.0 + 0.5)
|
||||
|
@ -893,8 +893,7 @@ func (rr *RRSIG) parse(c *zlexer, o string) *ParseError {
|
|||
l, _ = c.Next()
|
||||
if i, err := StringToTime(l.token); err != nil {
|
||||
// Try to see if all numeric and use it as epoch
|
||||
if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
|
||||
// TODO(miek): error out on > MAX_UINT32, same below
|
||||
if i, err := strconv.ParseUint(l.token, 10, 32); err == nil {
|
||||
rr.Expiration = uint32(i)
|
||||
} else {
|
||||
return &ParseError{"", "bad RRSIG Expiration", l}
|
||||
|
@ -906,7 +905,7 @@ func (rr *RRSIG) parse(c *zlexer, o string) *ParseError {
|
|||
c.Next() // zBlank
|
||||
l, _ = c.Next()
|
||||
if i, err := StringToTime(l.token); err != nil {
|
||||
if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
|
||||
if i, err := strconv.ParseUint(l.token, 10, 32); err == nil {
|
||||
rr.Inception = uint32(i)
|
||||
} else {
|
||||
return &ParseError{"", "bad RRSIG Inception", l}
|
||||
|
|
|
@ -91,7 +91,7 @@ func (mux *ServeMux) HandleRemove(pattern string) {
|
|||
// are redirected to the parent zone (if that is also registered),
|
||||
// otherwise the child gets the query.
|
||||
//
|
||||
// If no handler is found, or there is no question, a standard SERVFAIL
|
||||
// If no handler is found, or there is no question, a standard REFUSED
|
||||
// message is returned
|
||||
func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
|
||||
var h Handler
|
||||
|
@ -102,7 +102,7 @@ func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
|
|||
if h != nil {
|
||||
h.ServeDNS(w, req)
|
||||
} else {
|
||||
HandleFailed(w, req)
|
||||
handleRefused(w, req)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,15 @@ type response struct {
|
|||
writer Writer // writer to output the raw DNS bits
|
||||
}
|
||||
|
||||
// handleRefused returns a HandlerFunc that returns REFUSED for every request it gets.
|
||||
func handleRefused(w ResponseWriter, r *Msg) {
|
||||
m := new(Msg)
|
||||
m.SetRcode(r, RcodeRefused)
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
|
||||
// Deprecated: This function is going away.
|
||||
func HandleFailed(w ResponseWriter, r *Msg) {
|
||||
m := new(Msg)
|
||||
m.SetRcode(r, RcodeServerFailure)
|
||||
|
|
|
@ -0,0 +1,773 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SVCBKey uint16
|
||||
|
||||
// Keys defined in draft-ietf-dnsop-svcb-https-02 Section 11.1.2
|
||||
const (
|
||||
SVCB_MANDATORY SVCBKey = 0
|
||||
SVCB_ALPN SVCBKey = 1
|
||||
SVCB_NO_DEFAULT_ALPN SVCBKey = 2
|
||||
SVCB_PORT SVCBKey = 3
|
||||
SVCB_IPV4HINT SVCBKey = 4
|
||||
SVCB_ECHCONFIG SVCBKey = 5
|
||||
SVCB_IPV6HINT SVCBKey = 6
|
||||
svcb_RESERVED SVCBKey = 65535
|
||||
)
|
||||
|
||||
var svcbKeyToStringMap = map[SVCBKey]string{
|
||||
SVCB_MANDATORY: "mandatory",
|
||||
SVCB_ALPN: "alpn",
|
||||
SVCB_NO_DEFAULT_ALPN: "no-default-alpn",
|
||||
SVCB_PORT: "port",
|
||||
SVCB_IPV4HINT: "ipv4hint",
|
||||
SVCB_ECHCONFIG: "echconfig",
|
||||
SVCB_IPV6HINT: "ipv6hint",
|
||||
}
|
||||
|
||||
var svcbStringToKeyMap = reverseSVCBKeyMap(svcbKeyToStringMap)
|
||||
|
||||
func reverseSVCBKeyMap(m map[SVCBKey]string) map[string]SVCBKey {
|
||||
n := make(map[string]SVCBKey, len(m))
|
||||
for u, s := range m {
|
||||
n[s] = u
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// String takes the numerical code of an SVCB key and returns its name.
|
||||
// Returns an empty string for reserved keys.
|
||||
// Accepts unassigned keys as well as experimental/private keys.
|
||||
func (key SVCBKey) String() string {
|
||||
if x := svcbKeyToStringMap[key]; x != "" {
|
||||
return x
|
||||
}
|
||||
if key == svcb_RESERVED {
|
||||
return ""
|
||||
}
|
||||
return "key" + strconv.FormatUint(uint64(key), 10)
|
||||
}
|
||||
|
||||
// svcbStringToKey returns the numerical code of an SVCB key.
|
||||
// Returns svcb_RESERVED for reserved/invalid keys.
|
||||
// Accepts unassigned keys as well as experimental/private keys.
|
||||
func svcbStringToKey(s string) SVCBKey {
|
||||
if strings.HasPrefix(s, "key") {
|
||||
a, err := strconv.ParseUint(s[3:], 10, 16)
|
||||
// no leading zeros
|
||||
// key shouldn't be registered
|
||||
if err != nil || a == 65535 || s[3] == '0' || svcbKeyToStringMap[SVCBKey(a)] != "" {
|
||||
return svcb_RESERVED
|
||||
}
|
||||
return SVCBKey(a)
|
||||
}
|
||||
if key, ok := svcbStringToKeyMap[s]; ok {
|
||||
return key
|
||||
}
|
||||
return svcb_RESERVED
|
||||
}
|
||||
|
||||
func (rr *SVCB) parse(c *zlexer, o string) *ParseError {
|
||||
l, _ := c.Next()
|
||||
i, e := strconv.ParseUint(l.token, 10, 16)
|
||||
if e != nil || l.err {
|
||||
return &ParseError{l.token, "bad SVCB priority", l}
|
||||
}
|
||||
rr.Priority = uint16(i)
|
||||
|
||||
c.Next() // zBlank
|
||||
l, _ = c.Next() // zString
|
||||
rr.Target = l.token
|
||||
|
||||
name, nameOk := toAbsoluteName(l.token, o)
|
||||
if l.err || !nameOk {
|
||||
return &ParseError{l.token, "bad SVCB Target", l}
|
||||
}
|
||||
rr.Target = name
|
||||
|
||||
// Values (if any)
|
||||
l, _ = c.Next()
|
||||
var xs []SVCBKeyValue
|
||||
// Helps require whitespace between pairs.
|
||||
// Prevents key1000="a"key1001=...
|
||||
canHaveNextKey := true
|
||||
for l.value != zNewline && l.value != zEOF {
|
||||
switch l.value {
|
||||
case zString:
|
||||
if !canHaveNextKey {
|
||||
// The key we can now read was probably meant to be
|
||||
// a part of the last value.
|
||||
return &ParseError{l.token, "bad SVCB value quotation", l}
|
||||
}
|
||||
|
||||
// In key=value pairs, value does not have to be quoted unless value
|
||||
// contains whitespace. And keys don't need to have values.
|
||||
// Similarly, keys with an equality signs after them don't need values.
|
||||
// l.token includes at least up to the first equality sign.
|
||||
idx := strings.IndexByte(l.token, '=')
|
||||
var key, value string
|
||||
if idx < 0 {
|
||||
// Key with no value and no equality sign
|
||||
key = l.token
|
||||
} else if idx == 0 {
|
||||
return &ParseError{l.token, "bad SVCB key", l}
|
||||
} else {
|
||||
key, value = l.token[:idx], l.token[idx+1:]
|
||||
|
||||
if value == "" {
|
||||
// We have a key and an equality sign. Maybe we have nothing
|
||||
// after "=" or we have a double quote.
|
||||
l, _ = c.Next()
|
||||
if l.value == zQuote {
|
||||
// Only needed when value ends with double quotes.
|
||||
// Any value starting with zQuote ends with it.
|
||||
canHaveNextKey = false
|
||||
|
||||
l, _ = c.Next()
|
||||
switch l.value {
|
||||
case zString:
|
||||
// We have a value in double quotes.
|
||||
value = l.token
|
||||
l, _ = c.Next()
|
||||
if l.value != zQuote {
|
||||
return &ParseError{l.token, "SVCB unterminated value", l}
|
||||
}
|
||||
case zQuote:
|
||||
// There's nothing in double quotes.
|
||||
default:
|
||||
return &ParseError{l.token, "bad SVCB value", l}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
kv := makeSVCBKeyValue(svcbStringToKey(key))
|
||||
if kv == nil {
|
||||
return &ParseError{l.token, "bad SVCB key", l}
|
||||
}
|
||||
if err := kv.parse(value); err != nil {
|
||||
return &ParseError{l.token, err.Error(), l}
|
||||
}
|
||||
xs = append(xs, kv)
|
||||
case zQuote:
|
||||
return &ParseError{l.token, "SVCB key can't contain double quotes", l}
|
||||
case zBlank:
|
||||
canHaveNextKey = true
|
||||
default:
|
||||
return &ParseError{l.token, "bad SVCB values", l}
|
||||
}
|
||||
l, _ = c.Next()
|
||||
}
|
||||
rr.Value = xs
|
||||
if rr.Priority == 0 && len(xs) > 0 {
|
||||
return &ParseError{l.token, "SVCB aliasform can't have values", l}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeSVCBKeyValue returns an SVCBKeyValue struct with the key
|
||||
// or nil for reserved keys.
|
||||
func makeSVCBKeyValue(key SVCBKey) SVCBKeyValue {
|
||||
switch key {
|
||||
case SVCB_MANDATORY:
|
||||
return new(SVCBMandatory)
|
||||
case SVCB_ALPN:
|
||||
return new(SVCBAlpn)
|
||||
case SVCB_NO_DEFAULT_ALPN:
|
||||
return new(SVCBNoDefaultAlpn)
|
||||
case SVCB_PORT:
|
||||
return new(SVCBPort)
|
||||
case SVCB_IPV4HINT:
|
||||
return new(SVCBIPv4Hint)
|
||||
case SVCB_ECHCONFIG:
|
||||
return new(SVCBECHConfig)
|
||||
case SVCB_IPV6HINT:
|
||||
return new(SVCBIPv6Hint)
|
||||
case svcb_RESERVED:
|
||||
return nil
|
||||
default:
|
||||
e := new(SVCBLocal)
|
||||
e.KeyCode = key
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
// SVCB RR. See RFC xxxx (https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-00)
|
||||
|
||||
// The one with the smallest priority should be given preference. Of those with
|
||||
// equal priority, a random one should be preferred for load balancing.
|
||||
type SVCB struct {
|
||||
Hdr RR_Header
|
||||
Priority uint16
|
||||
Target string `dns:"domain-name"`
|
||||
Value []SVCBKeyValue `dns:"pairs"` // This must be empty if Priority is non-zero
|
||||
}
|
||||
|
||||
// HTTPS RR. Everything valid for SVCB applies to HTTPS as well
|
||||
// except that the HTTPS record is intended for use with the HTTP and HTTPS protocols.
|
||||
type HTTPS struct {
|
||||
SVCB
|
||||
}
|
||||
|
||||
func (rr *HTTPS) String() string {
|
||||
return rr.SVCB.String()
|
||||
}
|
||||
|
||||
func (rr *HTTPS) parse(c *zlexer, o string) *ParseError {
|
||||
return rr.SVCB.parse(c, o)
|
||||
}
|
||||
|
||||
// SVCBKeyValue defines a key=value pair for the SVCB RR type.
|
||||
// An SVCB RR can have multiple SVCBKeyValues appended to it.
|
||||
type SVCBKeyValue interface {
|
||||
// Key returns the numerical key code.
|
||||
Key() SVCBKey
|
||||
// pack returns the encoded value.
|
||||
pack() ([]byte, error)
|
||||
// unpack sets the value.
|
||||
unpack([]byte) error
|
||||
// String returns the string representation of the value.
|
||||
String() string
|
||||
// parse sets the value to the given string representation of the value.
|
||||
parse(string) error
|
||||
// copy returns a deep-copy of the pair.
|
||||
copy() SVCBKeyValue
|
||||
// len returns the length of value in the wire format.
|
||||
len() int
|
||||
}
|
||||
|
||||
// SVCBMandatory pair adds to required keys that must be interpreted for the RR
|
||||
// to be functional.
|
||||
// Basic use pattern for creating a mandatory option:
|
||||
//
|
||||
// o := new(dns.SVCB)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.TypeSVCB
|
||||
// e := new(dns.SVCBMandatory)
|
||||
// e.Code = []uint16{65403}
|
||||
// o.Value = append(o.Value, e)
|
||||
// // Then add key-value pair for key65403
|
||||
type SVCBMandatory struct {
|
||||
Code []SVCBKey // Must not include mandatory
|
||||
}
|
||||
|
||||
func (*SVCBMandatory) Key() SVCBKey { return SVCB_MANDATORY }
|
||||
|
||||
func (s *SVCBMandatory) String() string {
|
||||
str := make([]string, len(s.Code))
|
||||
for i, e := range s.Code {
|
||||
str[i] = e.String()
|
||||
}
|
||||
return strings.Join(str, ",")
|
||||
}
|
||||
|
||||
func (s *SVCBMandatory) pack() ([]byte, error) {
|
||||
codes := append([]SVCBKey(nil), s.Code...)
|
||||
sort.Slice(codes, func(i, j int) bool {
|
||||
return codes[i] < codes[j]
|
||||
})
|
||||
b := make([]byte, 2*len(codes))
|
||||
for i, e := range codes {
|
||||
binary.BigEndian.PutUint16(b[2*i:], uint16(e))
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (s *SVCBMandatory) unpack(b []byte) error {
|
||||
if len(b)%2 != 0 {
|
||||
return errors.New("dns: svcbmandatory: value length is not a multiple of 2")
|
||||
}
|
||||
codes := make([]SVCBKey, 0, len(b)/2)
|
||||
for i := 0; i < len(b); i += 2 {
|
||||
// We assume strictly increasing order.
|
||||
codes = append(codes, SVCBKey(binary.BigEndian.Uint16(b[i:])))
|
||||
}
|
||||
s.Code = codes
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SVCBMandatory) parse(b string) error {
|
||||
str := strings.Split(b, ",")
|
||||
codes := make([]SVCBKey, 0, len(str))
|
||||
for _, e := range str {
|
||||
codes = append(codes, svcbStringToKey(e))
|
||||
}
|
||||
s.Code = codes
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SVCBMandatory) len() int {
|
||||
return 2 * len(s.Code)
|
||||
}
|
||||
|
||||
func (s *SVCBMandatory) copy() SVCBKeyValue {
|
||||
return &SVCBMandatory{
|
||||
append([]SVCBKey(nil), s.Code...),
|
||||
}
|
||||
}
|
||||
|
||||
// SVCBAlpn pair is used to list supported connection protocols.
|
||||
// Protocol ids can be found at:
|
||||
// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
|
||||
// Basic use pattern for creating an alpn option:
|
||||
//
|
||||
// o := new(dns.HTTPS)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.TypeHTTPS
|
||||
// e := new(dns.SVCBAlpn)
|
||||
// e.Alpn = []string{"h2", "http/1.1"}
|
||||
// o.Value = append(o.Value, e)
|
||||
type SVCBAlpn struct {
|
||||
Alpn []string
|
||||
}
|
||||
|
||||
func (*SVCBAlpn) Key() SVCBKey { return SVCB_ALPN }
|
||||
func (s *SVCBAlpn) String() string { return strings.Join(s.Alpn, ",") }
|
||||
|
||||
// The spec requires the alpn keys including \ or , to be escaped.
|
||||
// In practice, no standard key including those exists.
|
||||
// Therefore those characters are not escaped.
|
||||
|
||||
func (s *SVCBAlpn) pack() ([]byte, error) {
|
||||
// Liberally estimate the size of an alpn as 10 octets
|
||||
b := make([]byte, 0, 10*len(s.Alpn))
|
||||
for _, e := range s.Alpn {
|
||||
if len(e) == 0 {
|
||||
return nil, errors.New("dns: svcbalpn: empty alpn-id")
|
||||
}
|
||||
if len(e) > 255 {
|
||||
return nil, errors.New("dns: svcbalpn: alpn-id too long")
|
||||
}
|
||||
b = append(b, byte(len(e)))
|
||||
b = append(b, e...)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (s *SVCBAlpn) unpack(b []byte) error {
|
||||
// Estimate the size of the smallest alpn as 4 bytes
|
||||
alpn := make([]string, 0, len(b)/4)
|
||||
for i := 0; i < len(b); {
|
||||
length := int(b[i])
|
||||
i++
|
||||
if i+length > len(b) {
|
||||
return errors.New("dns: svcbalpn: alpn array overflowing")
|
||||
}
|
||||
alpn = append(alpn, string(b[i:i+length]))
|
||||
i += length
|
||||
}
|
||||
s.Alpn = alpn
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SVCBAlpn) parse(b string) error {
|
||||
s.Alpn = strings.Split(b, ",")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SVCBAlpn) len() int {
|
||||
var l int
|
||||
for _, e := range s.Alpn {
|
||||
l += 1 + len(e)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func (s *SVCBAlpn) copy() SVCBKeyValue {
|
||||
return &SVCBAlpn{
|
||||
append([]string(nil), s.Alpn...),
|
||||
}
|
||||
}
|
||||
|
||||
// SVCBNoDefaultAlpn pair signifies no support for default connection protocols.
|
||||
// Basic use pattern for creating a no-default-alpn option:
|
||||
//
|
||||
// o := new(dns.SVCB)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.SVCB
|
||||
// e := new(dns.SVCBNoDefaultAlpn)
|
||||
// o.Value = append(o.Value, e)
|
||||
type SVCBNoDefaultAlpn struct {
|
||||
// Empty
|
||||
}
|
||||
|
||||
func (*SVCBNoDefaultAlpn) Key() SVCBKey { return SVCB_NO_DEFAULT_ALPN }
|
||||
func (*SVCBNoDefaultAlpn) copy() SVCBKeyValue { return &SVCBNoDefaultAlpn{} }
|
||||
func (*SVCBNoDefaultAlpn) pack() ([]byte, error) { return []byte{}, nil }
|
||||
func (*SVCBNoDefaultAlpn) String() string { return "" }
|
||||
func (*SVCBNoDefaultAlpn) len() int { return 0 }
|
||||
|
||||
func (*SVCBNoDefaultAlpn) unpack(b []byte) error {
|
||||
if len(b) != 0 {
|
||||
return errors.New("dns: svcbnodefaultalpn: no_default_alpn must have no value")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*SVCBNoDefaultAlpn) parse(b string) error {
|
||||
if len(b) != 0 {
|
||||
return errors.New("dns: svcbnodefaultalpn: no_default_alpn must have no value")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SVCBPort pair defines the port for connection.
|
||||
// Basic use pattern for creating a port option:
|
||||
//
|
||||
// o := new(dns.SVCB)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.SVCB
|
||||
// e := new(dns.SVCBPort)
|
||||
// e.Port = 80
|
||||
// o.Value = append(o.Value, e)
|
||||
type SVCBPort struct {
|
||||
Port uint16
|
||||
}
|
||||
|
||||
func (*SVCBPort) Key() SVCBKey { return SVCB_PORT }
|
||||
func (*SVCBPort) len() int { return 2 }
|
||||
func (s *SVCBPort) String() string { return strconv.FormatUint(uint64(s.Port), 10) }
|
||||
func (s *SVCBPort) copy() SVCBKeyValue { return &SVCBPort{s.Port} }
|
||||
|
||||
func (s *SVCBPort) unpack(b []byte) error {
|
||||
if len(b) != 2 {
|
||||
return errors.New("dns: svcbport: port length is not exactly 2 octets")
|
||||
}
|
||||
s.Port = binary.BigEndian.Uint16(b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SVCBPort) pack() ([]byte, error) {
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, s.Port)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (s *SVCBPort) parse(b string) error {
|
||||
port, err := strconv.ParseUint(b, 10, 16)
|
||||
if err != nil {
|
||||
return errors.New("dns: svcbport: port out of range")
|
||||
}
|
||||
s.Port = uint16(port)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SVCBIPv4Hint pair suggests an IPv4 address which may be used to open connections
|
||||
// if A and AAAA record responses for SVCB's Target domain haven't been received.
|
||||
// In that case, optionally, A and AAAA requests can be made, after which the connection
|
||||
// to the hinted IP address may be terminated and a new connection may be opened.
|
||||
// Basic use pattern for creating an ipv4hint option:
|
||||
//
|
||||
// o := new(dns.HTTPS)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.HTTPS
|
||||
// e := new(dns.SVCBIPv4Hint)
|
||||
// e.Hint = []net.IP{net.IPv4(1,1,1,1).To4()}
|
||||
// // or
|
||||
// e.Hint = []net.IP{net.ParseIP("1.1.1.1").To4()}
|
||||
// o.Value = append(o.Value, e)
|
||||
type SVCBIPv4Hint struct {
|
||||
Hint []net.IP
|
||||
}
|
||||
|
||||
func (*SVCBIPv4Hint) Key() SVCBKey { return SVCB_IPV4HINT }
|
||||
func (s *SVCBIPv4Hint) len() int { return 4 * len(s.Hint) }
|
||||
|
||||
func (s *SVCBIPv4Hint) pack() ([]byte, error) {
|
||||
b := make([]byte, 0, 4*len(s.Hint))
|
||||
for _, e := range s.Hint {
|
||||
x := e.To4()
|
||||
if x == nil {
|
||||
return nil, errors.New("dns: svcbipv4hint: expected ipv4, hint is ipv6")
|
||||
}
|
||||
b = append(b, x...)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (s *SVCBIPv4Hint) unpack(b []byte) error {
|
||||
if len(b) == 0 || len(b)%4 != 0 {
|
||||
return errors.New("dns: svcbipv4hint: ipv4 address byte array length is not a multiple of 4")
|
||||
}
|
||||
x := make([]net.IP, 0, len(b)/4)
|
||||
for i := 0; i < len(b); i += 4 {
|
||||
x = append(x, net.IP(b[i:i+4]))
|
||||
}
|
||||
s.Hint = x
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns the string form of s, it returns "<nil>" if s is invalid.
|
||||
func (s *SVCBIPv4Hint) String() string {
|
||||
str := make([]string, len(s.Hint))
|
||||
for i, e := range s.Hint {
|
||||
x := e.To4()
|
||||
if x == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
str[i] = x.String()
|
||||
}
|
||||
return strings.Join(str, ",")
|
||||
}
|
||||
|
||||
func (s *SVCBIPv4Hint) parse(b string) error {
|
||||
if strings.Contains(b, ":") {
|
||||
return errors.New("dns: svcbipv4hint: expected ipv4, got ipv6")
|
||||
}
|
||||
str := strings.Split(b, ",")
|
||||
dst := make([]net.IP, len(str))
|
||||
for i, e := range str {
|
||||
ip := net.ParseIP(e).To4()
|
||||
if ip == nil {
|
||||
return errors.New("dns: svcbipv4hint: bad ip")
|
||||
}
|
||||
dst[i] = ip
|
||||
}
|
||||
s.Hint = dst
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SVCBIPv4Hint) copy() SVCBKeyValue {
|
||||
return &SVCBIPv4Hint{
|
||||
append([]net.IP(nil), s.Hint...),
|
||||
}
|
||||
}
|
||||
|
||||
// SVCBECHConfig pair contains the ECHConfig structure defined in draft-ietf-tls-esni [RFC xxxx].
|
||||
// Basic use pattern for creating an echconfig option:
|
||||
//
|
||||
// o := new(dns.HTTPS)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.HTTPS
|
||||
// e := new(dns.SVCBECHConfig)
|
||||
// e.ECH = "/wH...="
|
||||
// o.Value = append(o.Value, e)
|
||||
type SVCBECHConfig struct {
|
||||
ECH []byte
|
||||
}
|
||||
|
||||
func (*SVCBECHConfig) Key() SVCBKey { return SVCB_ECHCONFIG }
|
||||
func (s *SVCBECHConfig) String() string { return toBase64(s.ECH) }
|
||||
func (s *SVCBECHConfig) len() int { return len(s.ECH) }
|
||||
|
||||
func (s *SVCBECHConfig) pack() ([]byte, error) {
|
||||
return append([]byte(nil), s.ECH...), nil
|
||||
}
|
||||
|
||||
func (s *SVCBECHConfig) copy() SVCBKeyValue {
|
||||
return &SVCBECHConfig{
|
||||
append([]byte(nil), s.ECH...),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SVCBECHConfig) unpack(b []byte) error {
|
||||
s.ECH = append([]byte(nil), b...)
|
||||
return nil
|
||||
}
|
||||
func (s *SVCBECHConfig) parse(b string) error {
|
||||
x, err := fromBase64([]byte(b))
|
||||
if err != nil {
|
||||
return errors.New("dns: svcbechconfig: bad base64 echconfig")
|
||||
}
|
||||
s.ECH = x
|
||||
return nil
|
||||
}
|
||||
|
||||
// SVCBIPv6Hint pair suggests an IPv6 address which may be used to open connections
|
||||
// if A and AAAA record responses for SVCB's Target domain haven't been received.
|
||||
// In that case, optionally, A and AAAA requests can be made, after which the
|
||||
// connection to the hinted IP address may be terminated and a new connection may be opened.
|
||||
// Basic use pattern for creating an ipv6hint option:
|
||||
//
|
||||
// o := new(dns.HTTPS)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.HTTPS
|
||||
// e := new(dns.SVCBIPv6Hint)
|
||||
// e.Hint = []net.IP{net.ParseIP("2001:db8::1")}
|
||||
// o.Value = append(o.Value, e)
|
||||
type SVCBIPv6Hint struct {
|
||||
Hint []net.IP
|
||||
}
|
||||
|
||||
func (*SVCBIPv6Hint) Key() SVCBKey { return SVCB_IPV6HINT }
|
||||
func (s *SVCBIPv6Hint) len() int { return 16 * len(s.Hint) }
|
||||
|
||||
func (s *SVCBIPv6Hint) pack() ([]byte, error) {
|
||||
b := make([]byte, 0, 16*len(s.Hint))
|
||||
for _, e := range s.Hint {
|
||||
if len(e) != net.IPv6len || e.To4() != nil {
|
||||
return nil, errors.New("dns: svcbipv6hint: expected ipv6, hint is ipv4")
|
||||
}
|
||||
b = append(b, e...)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (s *SVCBIPv6Hint) unpack(b []byte) error {
|
||||
if len(b) == 0 || len(b)%16 != 0 {
|
||||
return errors.New("dns: svcbipv6hint: ipv6 address byte array length not a multiple of 16")
|
||||
}
|
||||
x := make([]net.IP, 0, len(b)/16)
|
||||
for i := 0; i < len(b); i += 16 {
|
||||
ip := net.IP(b[i : i+16])
|
||||
if ip.To4() != nil {
|
||||
return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4")
|
||||
}
|
||||
x = append(x, ip)
|
||||
}
|
||||
s.Hint = x
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns the string form of s, it returns "<nil>" if s is invalid.
|
||||
func (s *SVCBIPv6Hint) String() string {
|
||||
str := make([]string, len(s.Hint))
|
||||
for i, e := range s.Hint {
|
||||
if x := e.To4(); x != nil {
|
||||
return "<nil>"
|
||||
}
|
||||
str[i] = e.String()
|
||||
}
|
||||
return strings.Join(str, ",")
|
||||
}
|
||||
|
||||
func (s *SVCBIPv6Hint) parse(b string) error {
|
||||
if strings.Contains(b, ".") {
|
||||
return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4")
|
||||
}
|
||||
str := strings.Split(b, ",")
|
||||
dst := make([]net.IP, len(str))
|
||||
for i, e := range str {
|
||||
ip := net.ParseIP(e)
|
||||
if ip == nil {
|
||||
return errors.New("dns: svcbipv6hint: bad ip")
|
||||
}
|
||||
dst[i] = ip
|
||||
}
|
||||
s.Hint = dst
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SVCBIPv6Hint) copy() SVCBKeyValue {
|
||||
return &SVCBIPv6Hint{
|
||||
append([]net.IP(nil), s.Hint...),
|
||||
}
|
||||
}
|
||||
|
||||
// SVCBLocal pair is intended for experimental/private use. The key is recommended
|
||||
// to be in the range [SVCB_PRIVATE_LOWER, SVCB_PRIVATE_UPPER].
|
||||
// Basic use pattern for creating a keyNNNNN option:
|
||||
//
|
||||
// o := new(dns.HTTPS)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.HTTPS
|
||||
// e := new(dns.SVCBLocal)
|
||||
// e.KeyCode = 65400
|
||||
// e.Data = []byte("abc")
|
||||
// o.Value = append(o.Value, e)
|
||||
type SVCBLocal struct {
|
||||
KeyCode SVCBKey // Never 65535 or any assigned keys
|
||||
Data []byte // All byte sequences are allowed
|
||||
}
|
||||
|
||||
func (s *SVCBLocal) Key() SVCBKey { return s.KeyCode }
|
||||
func (s *SVCBLocal) pack() ([]byte, error) { return append([]byte(nil), s.Data...), nil }
|
||||
func (s *SVCBLocal) len() int { return len(s.Data) }
|
||||
|
||||
func (s *SVCBLocal) unpack(b []byte) error {
|
||||
s.Data = append([]byte(nil), b...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SVCBLocal) String() string {
|
||||
var str strings.Builder
|
||||
str.Grow(4 * len(s.Data))
|
||||
for _, e := range s.Data {
|
||||
if ' ' <= e && e <= '~' {
|
||||
switch e {
|
||||
case '"', ';', ' ', '\\':
|
||||
str.WriteByte('\\')
|
||||
str.WriteByte(e)
|
||||
default:
|
||||
str.WriteByte(e)
|
||||
}
|
||||
} else {
|
||||
str.WriteString(escapeByte(e))
|
||||
}
|
||||
}
|
||||
return str.String()
|
||||
}
|
||||
|
||||
func (s *SVCBLocal) parse(b string) error {
|
||||
data := make([]byte, 0, len(b))
|
||||
for i := 0; i < len(b); {
|
||||
if b[i] != '\\' {
|
||||
data = append(data, b[i])
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if i+1 == len(b) {
|
||||
return errors.New("dns: svcblocal: svcb private/experimental key escape unterminated")
|
||||
}
|
||||
if isDigit(b[i+1]) {
|
||||
if i+3 < len(b) && isDigit(b[i+2]) && isDigit(b[i+3]) {
|
||||
a, err := strconv.ParseUint(b[i+1:i+4], 10, 8)
|
||||
if err == nil {
|
||||
i += 4
|
||||
data = append(data, byte(a))
|
||||
continue
|
||||
}
|
||||
}
|
||||
return errors.New("dns: svcblocal: svcb private/experimental key bad escaped octet")
|
||||
} else {
|
||||
data = append(data, b[i+1])
|
||||
i += 2
|
||||
}
|
||||
}
|
||||
s.Data = data
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SVCBLocal) copy() SVCBKeyValue {
|
||||
return &SVCBLocal{s.KeyCode,
|
||||
append([]byte(nil), s.Data...),
|
||||
}
|
||||
}
|
||||
|
||||
func (rr *SVCB) String() string {
|
||||
s := rr.Hdr.String() +
|
||||
strconv.Itoa(int(rr.Priority)) + " " +
|
||||
sprintName(rr.Target)
|
||||
for _, e := range rr.Value {
|
||||
s += " " + e.Key().String() + "=\"" + e.String() + "\""
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// areSVCBPairArraysEqual checks if SVCBKeyValue arrays are equal after sorting their
|
||||
// copies. arrA and arrB have equal lengths, otherwise zduplicate.go wouldn't call this function.
|
||||
func areSVCBPairArraysEqual(a []SVCBKeyValue, b []SVCBKeyValue) bool {
|
||||
a = append([]SVCBKeyValue(nil), a...)
|
||||
b = append([]SVCBKeyValue(nil), b...)
|
||||
sort.Slice(a, func(i, j int) bool { return a[i].Key() < a[j].Key() })
|
||||
sort.Slice(b, func(i, j int) bool { return b[i].Key() < b[j].Key() })
|
||||
for i, e := range a {
|
||||
if e.Key() != b[i].Key() {
|
||||
return false
|
||||
}
|
||||
b1, err1 := e.pack()
|
||||
b2, err2 := b[i].pack()
|
||||
if err1 != nil || err2 != nil || !bytes.Equal(b1, b2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -81,6 +81,8 @@ const (
|
|||
TypeCDNSKEY uint16 = 60
|
||||
TypeOPENPGPKEY uint16 = 61
|
||||
TypeCSYNC uint16 = 62
|
||||
TypeSVCB uint16 = 64
|
||||
TypeHTTPS uint16 = 65
|
||||
TypeSPF uint16 = 99
|
||||
TypeUINFO uint16 = 100
|
||||
TypeUID uint16 = 101
|
||||
|
|
|
@ -3,7 +3,7 @@ package dns
|
|||
import "fmt"
|
||||
|
||||
// Version is current version of this library.
|
||||
var Version = v{1, 1, 31}
|
||||
var Version = v{1, 1, 32}
|
||||
|
||||
// v holds the version of this library.
|
||||
type v struct {
|
||||
|
|
|
@ -402,6 +402,27 @@ func (r1 *HIP) isDuplicate(_r2 RR) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (r1 *HTTPS) isDuplicate(_r2 RR) bool {
|
||||
r2, ok := _r2.(*HTTPS)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
_ = r2
|
||||
if r1.Priority != r2.Priority {
|
||||
return false
|
||||
}
|
||||
if !isDuplicateName(r1.Target, r2.Target) {
|
||||
return false
|
||||
}
|
||||
if len(r1.Value) != len(r2.Value) {
|
||||
return false
|
||||
}
|
||||
if !areSVCBPairArraysEqual(r1.Value, r2.Value) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (r1 *KEY) isDuplicate(_r2 RR) bool {
|
||||
r2, ok := _r2.(*KEY)
|
||||
if !ok {
|
||||
|
@ -1076,6 +1097,27 @@ func (r1 *SSHFP) isDuplicate(_r2 RR) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (r1 *SVCB) isDuplicate(_r2 RR) bool {
|
||||
r2, ok := _r2.(*SVCB)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
_ = r2
|
||||
if r1.Priority != r2.Priority {
|
||||
return false
|
||||
}
|
||||
if !isDuplicateName(r1.Target, r2.Target) {
|
||||
return false
|
||||
}
|
||||
if len(r1.Value) != len(r2.Value) {
|
||||
return false
|
||||
}
|
||||
if !areSVCBPairArraysEqual(r1.Value, r2.Value) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (r1 *TA) isDuplicate(_r2 RR) bool {
|
||||
r2, ok := _r2.(*TA)
|
||||
if !ok {
|
||||
|
|
|
@ -316,6 +316,22 @@ func (rr *HIP) pack(msg []byte, off int, compression compressionMap, compress bo
|
|||
return off, nil
|
||||
}
|
||||
|
||||
func (rr *HTTPS) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
|
||||
off, err = packUint16(rr.Priority, msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
off, err = packDomainName(rr.Target, msg, off, compression, false)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
off, err = packDataSVCB(rr.Value, msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func (rr *KEY) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
|
||||
off, err = packUint16(rr.Flags, msg, off)
|
||||
if err != nil {
|
||||
|
@ -906,6 +922,22 @@ func (rr *SSHFP) pack(msg []byte, off int, compression compressionMap, compress
|
|||
return off, nil
|
||||
}
|
||||
|
||||
func (rr *SVCB) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
|
||||
off, err = packUint16(rr.Priority, msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
off, err = packDomainName(rr.Target, msg, off, compression, false)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
off, err = packDataSVCB(rr.Value, msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func (rr *TA) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
|
||||
off, err = packUint16(rr.KeyTag, msg, off)
|
||||
if err != nil {
|
||||
|
@ -1559,6 +1591,31 @@ func (rr *HIP) unpack(msg []byte, off int) (off1 int, err error) {
|
|||
return off, nil
|
||||
}
|
||||
|
||||
func (rr *HTTPS) unpack(msg []byte, off int) (off1 int, err error) {
|
||||
rdStart := off
|
||||
_ = rdStart
|
||||
|
||||
rr.Priority, off, err = unpackUint16(msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
if off == len(msg) {
|
||||
return off, nil
|
||||
}
|
||||
rr.Target, off, err = UnpackDomainName(msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
if off == len(msg) {
|
||||
return off, nil
|
||||
}
|
||||
rr.Value, off, err = unpackDataSVCB(msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func (rr *KEY) unpack(msg []byte, off int) (off1 int, err error) {
|
||||
rdStart := off
|
||||
_ = rdStart
|
||||
|
@ -2461,6 +2518,31 @@ func (rr *SSHFP) unpack(msg []byte, off int) (off1 int, err error) {
|
|||
return off, nil
|
||||
}
|
||||
|
||||
func (rr *SVCB) unpack(msg []byte, off int) (off1 int, err error) {
|
||||
rdStart := off
|
||||
_ = rdStart
|
||||
|
||||
rr.Priority, off, err = unpackUint16(msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
if off == len(msg) {
|
||||
return off, nil
|
||||
}
|
||||
rr.Target, off, err = UnpackDomainName(msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
if off == len(msg) {
|
||||
return off, nil
|
||||
}
|
||||
rr.Value, off, err = unpackDataSVCB(msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func (rr *TA) unpack(msg []byte, off int) (off1 int, err error) {
|
||||
rdStart := off
|
||||
_ = rdStart
|
||||
|
|
|
@ -33,6 +33,7 @@ var TypeToRR = map[uint16]func() RR{
|
|||
TypeGPOS: func() RR { return new(GPOS) },
|
||||
TypeHINFO: func() RR { return new(HINFO) },
|
||||
TypeHIP: func() RR { return new(HIP) },
|
||||
TypeHTTPS: func() RR { return new(HTTPS) },
|
||||
TypeKEY: func() RR { return new(KEY) },
|
||||
TypeKX: func() RR { return new(KX) },
|
||||
TypeL32: func() RR { return new(L32) },
|
||||
|
@ -70,6 +71,7 @@ var TypeToRR = map[uint16]func() RR{
|
|||
TypeSPF: func() RR { return new(SPF) },
|
||||
TypeSRV: func() RR { return new(SRV) },
|
||||
TypeSSHFP: func() RR { return new(SSHFP) },
|
||||
TypeSVCB: func() RR { return new(SVCB) },
|
||||
TypeTA: func() RR { return new(TA) },
|
||||
TypeTALINK: func() RR { return new(TALINK) },
|
||||
TypeTKEY: func() RR { return new(TKEY) },
|
||||
|
@ -110,6 +112,7 @@ var TypeToString = map[uint16]string{
|
|||
TypeGPOS: "GPOS",
|
||||
TypeHINFO: "HINFO",
|
||||
TypeHIP: "HIP",
|
||||
TypeHTTPS: "HTTPS",
|
||||
TypeISDN: "ISDN",
|
||||
TypeIXFR: "IXFR",
|
||||
TypeKEY: "KEY",
|
||||
|
@ -153,6 +156,7 @@ var TypeToString = map[uint16]string{
|
|||
TypeSPF: "SPF",
|
||||
TypeSRV: "SRV",
|
||||
TypeSSHFP: "SSHFP",
|
||||
TypeSVCB: "SVCB",
|
||||
TypeTA: "TA",
|
||||
TypeTALINK: "TALINK",
|
||||
TypeTKEY: "TKEY",
|
||||
|
@ -191,6 +195,7 @@ func (rr *GID) Header() *RR_Header { return &rr.Hdr }
|
|||
func (rr *GPOS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *HINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *HIP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *HTTPS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *KEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *KX) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *L32) Header() *RR_Header { return &rr.Hdr }
|
||||
|
@ -229,6 +234,7 @@ func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
|
|||
func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SVCB) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TALINK) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
|
@ -592,6 +598,15 @@ func (rr *SSHFP) len(off int, compression map[string]struct{}) int {
|
|||
l += len(rr.FingerPrint) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *SVCB) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Priority
|
||||
l += domainNameLen(rr.Target, off+l, compression, false)
|
||||
for _, x := range rr.Value {
|
||||
l += 4 + int(x.len())
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *TA) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // KeyTag
|
||||
|
@ -753,6 +768,9 @@ func (rr *HIP) copy() RR {
|
|||
copy(RendezvousServers, rr.RendezvousServers)
|
||||
return &HIP{rr.Hdr, rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
|
||||
}
|
||||
func (rr *HTTPS) copy() RR {
|
||||
return &HTTPS{*rr.SVCB.copy().(*SVCB)}
|
||||
}
|
||||
func (rr *KEY) copy() RR {
|
||||
return &KEY{*rr.DNSKEY.copy().(*DNSKEY)}
|
||||
}
|
||||
|
@ -879,6 +897,13 @@ func (rr *SRV) copy() RR {
|
|||
func (rr *SSHFP) copy() RR {
|
||||
return &SSHFP{rr.Hdr, rr.Algorithm, rr.Type, rr.FingerPrint}
|
||||
}
|
||||
func (rr *SVCB) copy() RR {
|
||||
Value := make([]SVCBKeyValue, len(rr.Value))
|
||||
for i, e := range rr.Value {
|
||||
Value[i] = e.copy()
|
||||
}
|
||||
return &SVCB{rr.Hdr, rr.Priority, rr.Target, Value}
|
||||
}
|
||||
func (rr *TA) copy() RR {
|
||||
return &TA{rr.Hdr, rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package assert
|
||||
|
||||
import (
|
||||
io "io"
|
||||
http "net/http"
|
||||
url "net/url"
|
||||
time "time"
|
||||
|
@ -202,11 +201,11 @@ func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, arg
|
|||
// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
|
||||
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return HTTPBodyContains(t, handler, method, url, values, body, str, append([]interface{}{msg}, args...)...)
|
||||
return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
||||
|
@ -215,11 +214,11 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url
|
|||
// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
|
||||
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return HTTPBodyNotContains(t, handler, method, url, values, body, str, append([]interface{}{msg}, args...)...)
|
||||
return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// HTTPErrorf asserts that a specified handler returns an error status code.
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package assert
|
||||
|
||||
import (
|
||||
io "io"
|
||||
http "net/http"
|
||||
url "net/url"
|
||||
time "time"
|
||||
|
@ -386,11 +385,11 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args .
|
|||
// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
|
||||
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return HTTPBodyContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
|
||||
return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
||||
}
|
||||
|
||||
// HTTPBodyContainsf asserts that a specified handler returns a
|
||||
|
@ -399,11 +398,11 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u
|
|||
// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
|
||||
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return HTTPBodyContainsf(a.t, handler, method, url, values, body, str, msg, args...)
|
||||
return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
|
||||
}
|
||||
|
||||
// HTTPBodyNotContains asserts that a specified handler returns a
|
||||
|
@ -412,11 +411,11 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string,
|
|||
// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
|
||||
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return HTTPBodyNotContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
|
||||
return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
||||
}
|
||||
|
||||
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
||||
|
@ -425,11 +424,11 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string
|
|||
// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) bool {
|
||||
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return HTTPBodyNotContainsf(a.t, handler, method, url, values, body, str, msg, args...)
|
||||
return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
|
||||
}
|
||||
|
||||
// HTTPError asserts that a specified handler returns an error status code.
|
||||
|
|
|
@ -2,7 +2,6 @@ package assert
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
|
@ -112,13 +111,9 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va
|
|||
|
||||
// HTTPBody is a helper that returns HTTP body of the response. It returns
|
||||
// empty string if building a new request fails.
|
||||
func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values, body io.Reader) string {
|
||||
func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
if values != nil {
|
||||
url = url + "?" + values.Encode()
|
||||
}
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
@ -132,13 +127,13 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values, b
|
|||
// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
|
||||
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
httpBody := HTTPBody(handler, method, url, values, body)
|
||||
body := HTTPBody(handler, method, url, values)
|
||||
|
||||
contains := strings.Contains(httpBody, fmt.Sprint(str))
|
||||
contains := strings.Contains(body, fmt.Sprint(str))
|
||||
if !contains {
|
||||
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
|
||||
}
|
||||
|
@ -152,13 +147,13 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
|
|||
// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) bool {
|
||||
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
httpBody := HTTPBody(handler, method, url, values, body)
|
||||
body := HTTPBody(handler, method, url, values)
|
||||
|
||||
contains := strings.Contains(httpBody, fmt.Sprint(str))
|
||||
contains := strings.Contains(body, fmt.Sprint(str))
|
||||
if contains {
|
||||
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ package require
|
|||
|
||||
import (
|
||||
assert "github.com/stretchr/testify/assert"
|
||||
io "io"
|
||||
http "net/http"
|
||||
url "net/url"
|
||||
time "time"
|
||||
|
@ -489,11 +488,11 @@ func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...in
|
|||
// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
|
||||
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.HTTPBodyContains(t, handler, method, url, values, body, str, msgAndArgs...) {
|
||||
if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
|
@ -505,11 +504,11 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url s
|
|||
// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
|
||||
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.HTTPBodyContainsf(t, handler, method, url, values, body, str, msg, args...) {
|
||||
if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
|
@ -521,11 +520,11 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url
|
|||
// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
|
||||
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.HTTPBodyNotContains(t, handler, method, url, values, body, str, msgAndArgs...) {
|
||||
if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
|
@ -537,11 +536,11 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, ur
|
|||
// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
|
||||
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.HTTPBodyNotContainsf(t, handler, method, url, values, body, str, msg, args...) {
|
||||
if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
|
|
|
@ -7,7 +7,6 @@ package require
|
|||
|
||||
import (
|
||||
assert "github.com/stretchr/testify/assert"
|
||||
io "io"
|
||||
http "net/http"
|
||||
url "net/url"
|
||||
time "time"
|
||||
|
@ -387,11 +386,11 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args .
|
|||
// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
|
||||
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
HTTPBodyContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
|
||||
HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
||||
}
|
||||
|
||||
// HTTPBodyContainsf asserts that a specified handler returns a
|
||||
|
@ -400,11 +399,11 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u
|
|||
// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
|
||||
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
HTTPBodyContainsf(a.t, handler, method, url, values, body, str, msg, args...)
|
||||
HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
|
||||
}
|
||||
|
||||
// HTTPBodyNotContains asserts that a specified handler returns a
|
||||
|
@ -413,11 +412,11 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string,
|
|||
// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msgAndArgs ...interface{}) {
|
||||
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
HTTPBodyNotContains(a.t, handler, method, url, values, body, str, msgAndArgs...)
|
||||
HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
||||
}
|
||||
|
||||
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
||||
|
@ -426,11 +425,11 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string
|
|||
// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, body io.Reader, str interface{}, msg string, args ...interface{}) {
|
||||
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
HTTPBodyNotContainsf(a.t, handler, method, url, values, body, str, msg, args...)
|
||||
HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
|
||||
}
|
||||
|
||||
// HTTPError asserts that a specified handler returns an error status code.
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD and its
|
||||
// extended nonce variant XChaCha20-Poly1305, as specified in RFC 8439 and
|
||||
// draft-irtf-cfrg-xchacha-01.
|
||||
package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// KeySize is the size of the key used by this AEAD, in bytes.
|
||||
KeySize = 32
|
||||
|
||||
// NonceSize is the size of the nonce used with the standard variant of this
|
||||
// AEAD, in bytes.
|
||||
//
|
||||
// Note that this is too short to be safely generated at random if the same
|
||||
// key is reused more than 2³² times.
|
||||
NonceSize = 12
|
||||
|
||||
// NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305
|
||||
// variant of this AEAD, in bytes.
|
||||
NonceSizeX = 24
|
||||
)
|
||||
|
||||
type chacha20poly1305 struct {
|
||||
key [KeySize]byte
|
||||
}
|
||||
|
||||
// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
|
||||
func New(key []byte) (cipher.AEAD, error) {
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20poly1305: bad key length")
|
||||
}
|
||||
ret := new(chacha20poly1305)
|
||||
copy(ret.key[:], key)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) NonceSize() int {
|
||||
return NonceSize
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) Overhead() int {
|
||||
return 16
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if len(nonce) != NonceSize {
|
||||
panic("chacha20poly1305: bad nonce length passed to Seal")
|
||||
}
|
||||
|
||||
if uint64(len(plaintext)) > (1<<38)-64 {
|
||||
panic("chacha20poly1305: plaintext too large")
|
||||
}
|
||||
|
||||
return c.seal(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
var errOpen = errors.New("chacha20poly1305: message authentication failed")
|
||||
|
||||
func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if len(nonce) != NonceSize {
|
||||
panic("chacha20poly1305: bad nonce length passed to Open")
|
||||
}
|
||||
if len(ciphertext) < 16 {
|
||||
return nil, errOpen
|
||||
}
|
||||
if uint64(len(ciphertext)) > (1<<38)-48 {
|
||||
panic("chacha20poly1305: ciphertext too large")
|
||||
}
|
||||
|
||||
return c.open(dst, nonce, ciphertext, additionalData)
|
||||
}
|
||||
|
||||
// sliceForAppend takes a slice and a requested number of bytes. It returns a
|
||||
// slice with the contents of the given slice followed by that many bytes and a
|
||||
// second slice that aliases into it and contains only the extra bytes. If the
|
||||
// original slice has sufficient capacity then no allocation is performed.
|
||||
func sliceForAppend(in []byte, n int) (head, tail []byte) {
|
||||
if total := len(in) + n; cap(in) >= total {
|
||||
head = in[:total]
|
||||
} else {
|
||||
head = make([]byte, total)
|
||||
copy(head, in)
|
||||
}
|
||||
tail = head[len(in):]
|
||||
return
|
||||
}
|
86
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
Normal file
86
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !gccgo,!purego
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/crypto/internal/subtle"
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
|
||||
|
||||
//go:noescape
|
||||
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
|
||||
|
||||
var (
|
||||
useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
|
||||
)
|
||||
|
||||
// setupState writes a ChaCha20 input matrix to state. See
|
||||
// https://tools.ietf.org/html/rfc7539#section-2.3.
|
||||
func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
|
||||
state[0] = 0x61707865
|
||||
state[1] = 0x3320646e
|
||||
state[2] = 0x79622d32
|
||||
state[3] = 0x6b206574
|
||||
|
||||
state[4] = binary.LittleEndian.Uint32(key[0:4])
|
||||
state[5] = binary.LittleEndian.Uint32(key[4:8])
|
||||
state[6] = binary.LittleEndian.Uint32(key[8:12])
|
||||
state[7] = binary.LittleEndian.Uint32(key[12:16])
|
||||
state[8] = binary.LittleEndian.Uint32(key[16:20])
|
||||
state[9] = binary.LittleEndian.Uint32(key[20:24])
|
||||
state[10] = binary.LittleEndian.Uint32(key[24:28])
|
||||
state[11] = binary.LittleEndian.Uint32(key[28:32])
|
||||
|
||||
state[12] = 0
|
||||
state[13] = binary.LittleEndian.Uint32(nonce[0:4])
|
||||
state[14] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||
state[15] = binary.LittleEndian.Uint32(nonce[8:12])
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if !cpu.X86.HasSSSE3 {
|
||||
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
var state [16]uint32
|
||||
setupState(&state, &c.key, nonce)
|
||||
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+16)
|
||||
if subtle.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if !cpu.X86.HasSSSE3 {
|
||||
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||
}
|
||||
|
||||
var state [16]uint32
|
||||
setupState(&state, &c.key, nonce)
|
||||
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if subtle.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
}
|
||||
return nil, errOpen
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
2695
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
generated
vendored
Normal file
2695
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
81
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
generated
vendored
Normal file
81
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/crypto/chacha20"
|
||||
"golang.org/x/crypto/internal/subtle"
|
||||
"golang.org/x/crypto/poly1305"
|
||||
)
|
||||
|
||||
func writeWithPadding(p *poly1305.MAC, b []byte) {
|
||||
p.Write(b)
|
||||
if rem := len(b) % 16; rem != 0 {
|
||||
var buf [16]byte
|
||||
padLen := 16 - rem
|
||||
p.Write(buf[:padLen])
|
||||
}
|
||||
}
|
||||
|
||||
func writeUint64(p *poly1305.MAC, n int) {
|
||||
var buf [8]byte
|
||||
binary.LittleEndian.PutUint64(buf[:], uint64(n))
|
||||
p.Write(buf[:])
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
|
||||
ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
|
||||
if subtle.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
|
||||
var polyKey [32]byte
|
||||
s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
|
||||
s.XORKeyStream(polyKey[:], polyKey[:])
|
||||
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
|
||||
s.XORKeyStream(ciphertext, plaintext)
|
||||
|
||||
p := poly1305.New(&polyKey)
|
||||
writeWithPadding(p, additionalData)
|
||||
writeWithPadding(p, ciphertext)
|
||||
writeUint64(p, len(additionalData))
|
||||
writeUint64(p, len(plaintext))
|
||||
p.Sum(tag[:0])
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
tag := ciphertext[len(ciphertext)-16:]
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
|
||||
var polyKey [32]byte
|
||||
s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
|
||||
s.XORKeyStream(polyKey[:], polyKey[:])
|
||||
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
|
||||
|
||||
p := poly1305.New(&polyKey)
|
||||
writeWithPadding(p, additionalData)
|
||||
writeWithPadding(p, ciphertext)
|
||||
writeUint64(p, len(additionalData))
|
||||
writeUint64(p, len(ciphertext))
|
||||
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if subtle.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
if !p.Verify(tag) {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
}
|
||||
return nil, errOpen
|
||||
}
|
||||
|
||||
s.XORKeyStream(out, ciphertext)
|
||||
return ret, nil
|
||||
}
|
15
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
generated
vendored
Normal file
15
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !amd64 gccgo purego
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"errors"
|
||||
|
||||
"golang.org/x/crypto/chacha20"
|
||||
)
|
||||
|
||||
type xchacha20poly1305 struct {
|
||||
key [KeySize]byte
|
||||
}
|
||||
|
||||
// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key.
|
||||
//
|
||||
// XChaCha20-Poly1305 is a ChaCha20-Poly1305 variant that takes a longer nonce,
|
||||
// suitable to be generated randomly without risk of collisions. It should be
|
||||
// preferred when nonce uniqueness cannot be trivially ensured, or whenever
|
||||
// nonces are randomly generated.
|
||||
func NewX(key []byte) (cipher.AEAD, error) {
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20poly1305: bad key length")
|
||||
}
|
||||
ret := new(xchacha20poly1305)
|
||||
copy(ret.key[:], key)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (*xchacha20poly1305) NonceSize() int {
|
||||
return NonceSizeX
|
||||
}
|
||||
|
||||
func (*xchacha20poly1305) Overhead() int {
|
||||
return 16
|
||||
}
|
||||
|
||||
func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if len(nonce) != NonceSizeX {
|
||||
panic("chacha20poly1305: bad nonce length passed to Seal")
|
||||
}
|
||||
|
||||
// XChaCha20-Poly1305 technically supports a 64-bit counter, so there is no
|
||||
// size limit. However, since we reuse the ChaCha20-Poly1305 implementation,
|
||||
// the second half of the counter is not available. This is unlikely to be
|
||||
// an issue because the cipher.AEAD API requires the entire message to be in
|
||||
// memory, and the counter overflows at 256 GB.
|
||||
if uint64(len(plaintext)) > (1<<38)-64 {
|
||||
panic("chacha20poly1305: plaintext too large")
|
||||
}
|
||||
|
||||
c := new(chacha20poly1305)
|
||||
hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
|
||||
copy(c.key[:], hKey)
|
||||
|
||||
// The first 4 bytes of the final nonce are unused counter space.
|
||||
cNonce := make([]byte, NonceSize)
|
||||
copy(cNonce[4:12], nonce[16:24])
|
||||
|
||||
return c.seal(dst, cNonce[:], plaintext, additionalData)
|
||||
}
|
||||
|
||||
func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if len(nonce) != NonceSizeX {
|
||||
panic("chacha20poly1305: bad nonce length passed to Open")
|
||||
}
|
||||
if len(ciphertext) < 16 {
|
||||
return nil, errOpen
|
||||
}
|
||||
if uint64(len(ciphertext)) > (1<<38)-48 {
|
||||
panic("chacha20poly1305: ciphertext too large")
|
||||
}
|
||||
|
||||
c := new(chacha20poly1305)
|
||||
hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
|
||||
copy(c.key[:], hKey)
|
||||
|
||||
// The first 4 bytes of the final nonce are unused counter space.
|
||||
cNonce := make([]byte, NonceSize)
|
||||
copy(cNonce[4:12], nonce[16:24])
|
||||
|
||||
return c.open(dst, cNonce[:], ciphertext, additionalData)
|
||||
}
|
|
@ -1,19 +1,16 @@
|
|||
# git.schwanenlied.me/yawning/x448.git v0.0.0-20170617130356-01b048fb03d6
|
||||
git.schwanenlied.me/yawning/x448.git
|
||||
# github.com/BurntSushi/toml v0.3.1
|
||||
github.com/BurntSushi/toml
|
||||
# github.com/DATA-DOG/go-sqlmock v1.3.3
|
||||
## explicit
|
||||
github.com/DATA-DOG/go-sqlmock
|
||||
# github.com/acmacalister/skittles v0.0.0-20160609003031-7423546701e1
|
||||
## explicit
|
||||
github.com/acmacalister/skittles
|
||||
# github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
|
||||
## explicit
|
||||
github.com/alecthomas/units
|
||||
# github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239
|
||||
## explicit
|
||||
github.com/anmitsu/go-shlex
|
||||
# github.com/aws/aws-sdk-go v1.34.19
|
||||
## explicit
|
||||
github.com/aws/aws-sdk-go/aws
|
||||
github.com/aws/aws-sdk-go/aws/arn
|
||||
github.com/aws/aws-sdk-go/aws/awserr
|
||||
|
@ -64,24 +61,32 @@ github.com/caddyserver/caddy
|
|||
github.com/caddyserver/caddy/caddyfile
|
||||
github.com/caddyserver/caddy/telemetry
|
||||
# github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894
|
||||
## explicit
|
||||
github.com/certifi/gocertifi
|
||||
# github.com/cespare/xxhash/v2 v2.1.1
|
||||
github.com/cespare/xxhash/v2
|
||||
# github.com/cisco/go-hpke v0.0.0-20201023221920-2866d2aa0603
|
||||
github.com/cisco/go-hpke
|
||||
# github.com/cisco/go-tls-syntax v0.0.0-20200617162716-46b0cfb76b9b
|
||||
github.com/cisco/go-tls-syntax
|
||||
# github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93
|
||||
## explicit
|
||||
github.com/cloudflare/brotli-go
|
||||
github.com/cloudflare/brotli-go/brotli
|
||||
github.com/cloudflare/brotli-go/common
|
||||
github.com/cloudflare/brotli-go/dec
|
||||
github.com/cloudflare/brotli-go/enc
|
||||
# github.com/cloudflare/circl v1.0.0
|
||||
github.com/cloudflare/circl/dh/sidh
|
||||
github.com/cloudflare/circl/dh/sidh/internal/common
|
||||
github.com/cloudflare/circl/dh/sidh/internal/p503
|
||||
github.com/cloudflare/circl/dh/sidh/internal/p751
|
||||
github.com/cloudflare/circl/dh/sidh/internal/shake
|
||||
# github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc
|
||||
## explicit
|
||||
github.com/cloudflare/golibs/lrucache
|
||||
# github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58
|
||||
github.com/cloudflare/golz4
|
||||
# github.com/cloudflare/odoh-go v0.1.3
|
||||
github.com/cloudflare/odoh-go
|
||||
# github.com/coredns/coredns v1.7.0
|
||||
## explicit
|
||||
github.com/coredns/coredns/core/dnsserver
|
||||
github.com/coredns/coredns/coremain
|
||||
github.com/coredns/coredns/pb
|
||||
|
@ -109,45 +114,27 @@ github.com/coredns/coredns/plugin/pkg/uniq
|
|||
github.com/coredns/coredns/plugin/test
|
||||
github.com/coredns/coredns/request
|
||||
# github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73
|
||||
## explicit
|
||||
github.com/coreos/go-oidc/jose
|
||||
# github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||
## explicit
|
||||
github.com/coreos/go-systemd/daemon
|
||||
# github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d
|
||||
github.com/cpuguy83/go-md2man/v2/md2man
|
||||
# github.com/davecgh/go-spew v1.1.1
|
||||
github.com/davecgh/go-spew/spew
|
||||
# github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0
|
||||
## explicit
|
||||
github.com/denisenkom/go-mssqldb
|
||||
github.com/denisenkom/go-mssqldb/internal/cp
|
||||
github.com/denisenkom/go-mssqldb/internal/decimal
|
||||
github.com/denisenkom/go-mssqldb/internal/querytext
|
||||
# github.com/equinox-io/equinox v1.2.0
|
||||
## explicit
|
||||
# github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51
|
||||
## explicit
|
||||
# github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9
|
||||
## explicit
|
||||
# github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434
|
||||
## explicit
|
||||
github.com/facebookgo/grace/gracenet
|
||||
# github.com/facebookgo/stack v0.0.0-20160209184415-751773369052
|
||||
## explicit
|
||||
# github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870
|
||||
## explicit
|
||||
# github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
|
||||
github.com/flynn/go-shlex
|
||||
# github.com/frankban/quicktest v1.10.0
|
||||
## explicit
|
||||
# github.com/fsnotify/fsnotify v1.4.9
|
||||
## explicit
|
||||
github.com/fsnotify/fsnotify
|
||||
# github.com/gdamore/encoding v1.0.0
|
||||
github.com/gdamore/encoding
|
||||
# github.com/gdamore/tcell v1.3.0
|
||||
## explicit
|
||||
github.com/gdamore/tcell
|
||||
github.com/gdamore/tcell/terminfo
|
||||
github.com/gdamore/tcell/terminfo/a/adm3a
|
||||
|
@ -199,29 +186,22 @@ github.com/gdamore/tcell/terminfo/x/xnuppc
|
|||
github.com/gdamore/tcell/terminfo/x/xterm
|
||||
github.com/gdamore/tcell/terminfo/x/xterm_kitty
|
||||
# github.com/getsentry/raven-go v0.0.0-20180517221441-ed7bcb39ff10
|
||||
## explicit
|
||||
github.com/getsentry/raven-go
|
||||
# github.com/gliderlabs/ssh v0.0.0-20191009160644-63518b5243e0
|
||||
## explicit
|
||||
github.com/gliderlabs/ssh
|
||||
# github.com/go-sql-driver/mysql v1.5.0
|
||||
## explicit
|
||||
github.com/go-sql-driver/mysql
|
||||
# github.com/gobwas/httphead v0.0.0-20200921212729-da3d93bc3c58
|
||||
## explicit
|
||||
github.com/gobwas/httphead
|
||||
# github.com/gobwas/pool v0.2.1
|
||||
## explicit
|
||||
github.com/gobwas/pool
|
||||
github.com/gobwas/pool/internal/pmath
|
||||
github.com/gobwas/pool/pbufio
|
||||
github.com/gobwas/pool/pbytes
|
||||
# github.com/gobwas/ws v1.0.4
|
||||
## explicit
|
||||
github.com/gobwas/ws
|
||||
github.com/gobwas/ws/wsutil
|
||||
# github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
||||
## explicit
|
||||
github.com/golang-collections/collections/queue
|
||||
# github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe
|
||||
github.com/golang-sql/civil
|
||||
|
@ -231,32 +211,22 @@ github.com/golang/protobuf/ptypes
|
|||
github.com/golang/protobuf/ptypes/any
|
||||
github.com/golang/protobuf/ptypes/duration
|
||||
github.com/golang/protobuf/ptypes/timestamp
|
||||
# github.com/google/go-cmp v0.5.2
|
||||
## explicit
|
||||
# github.com/google/uuid v1.1.2
|
||||
## explicit
|
||||
github.com/google/uuid
|
||||
# github.com/gorilla/mux v1.7.3
|
||||
## explicit
|
||||
github.com/gorilla/mux
|
||||
# github.com/gorilla/websocket v1.4.2
|
||||
## explicit
|
||||
github.com/gorilla/websocket
|
||||
# github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645
|
||||
github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc
|
||||
# github.com/jmespath/go-jmespath v0.3.0
|
||||
github.com/jmespath/go-jmespath
|
||||
# github.com/jmoiron/sqlx v1.2.0
|
||||
## explicit
|
||||
github.com/jmoiron/sqlx
|
||||
github.com/jmoiron/sqlx/reflectx
|
||||
# github.com/json-iterator/go v1.1.10
|
||||
## explicit
|
||||
github.com/json-iterator/go
|
||||
# github.com/kr/text v0.2.0
|
||||
## explicit
|
||||
# github.com/kshvakov/clickhouse v1.3.11
|
||||
## explicit
|
||||
github.com/kshvakov/clickhouse
|
||||
github.com/kshvakov/clickhouse/lib/binary
|
||||
github.com/kshvakov/clickhouse/lib/cityhash102
|
||||
|
@ -267,10 +237,7 @@ github.com/kshvakov/clickhouse/lib/lz4
|
|||
github.com/kshvakov/clickhouse/lib/protocol
|
||||
github.com/kshvakov/clickhouse/lib/types
|
||||
github.com/kshvakov/clickhouse/lib/writebuffer
|
||||
# github.com/kylelemons/godebug v1.1.0
|
||||
## explicit
|
||||
# github.com/lib/pq v1.2.0
|
||||
## explicit
|
||||
github.com/lib/pq
|
||||
github.com/lib/pq/oid
|
||||
github.com/lib/pq/scram
|
||||
|
@ -279,47 +246,35 @@ github.com/lucasb-eyer/go-colorful
|
|||
# github.com/mattn/go-runewidth v0.0.8
|
||||
github.com/mattn/go-runewidth
|
||||
# github.com/mattn/go-sqlite3 v1.11.0
|
||||
## explicit
|
||||
github.com/mattn/go-sqlite3
|
||||
# github.com/matttproud/golang_protobuf_extensions v1.0.1
|
||||
github.com/matttproud/golang_protobuf_extensions/pbutil
|
||||
# github.com/miekg/dns v1.1.31
|
||||
## explicit
|
||||
# github.com/miekg/dns v1.1.32
|
||||
github.com/miekg/dns
|
||||
# github.com/mitchellh/go-homedir v1.1.0
|
||||
## explicit
|
||||
github.com/mitchellh/go-homedir
|
||||
# github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
|
||||
github.com/modern-go/concurrent
|
||||
# github.com/modern-go/reflect2 v1.0.1
|
||||
github.com/modern-go/reflect2
|
||||
# github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e
|
||||
## explicit
|
||||
# github.com/opentracing/opentracing-go v1.2.0
|
||||
## explicit
|
||||
github.com/opentracing/opentracing-go
|
||||
github.com/opentracing/opentracing-go/ext
|
||||
github.com/opentracing/opentracing-go/log
|
||||
# github.com/pierrec/lz4 v2.5.2+incompatible
|
||||
## explicit
|
||||
# github.com/pkg/errors v0.9.1
|
||||
## explicit
|
||||
github.com/pkg/errors
|
||||
# github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/pmezard/go-difflib/difflib
|
||||
# github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35
|
||||
## explicit
|
||||
github.com/pquerna/cachecontrol
|
||||
github.com/pquerna/cachecontrol/cacheobject
|
||||
# github.com/prometheus/client_golang v1.7.1
|
||||
## explicit
|
||||
github.com/prometheus/client_golang/prometheus
|
||||
github.com/prometheus/client_golang/prometheus/internal
|
||||
github.com/prometheus/client_golang/prometheus/promhttp
|
||||
# github.com/prometheus/client_model v0.2.0
|
||||
github.com/prometheus/client_model/go
|
||||
# github.com/prometheus/common v0.13.0
|
||||
## explicit
|
||||
github.com/prometheus/common/expfmt
|
||||
github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg
|
||||
github.com/prometheus/common/model
|
||||
|
@ -327,10 +282,7 @@ github.com/prometheus/common/model
|
|||
github.com/prometheus/procfs
|
||||
github.com/prometheus/procfs/internal/fs
|
||||
github.com/prometheus/procfs/internal/util
|
||||
# github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
|
||||
## explicit
|
||||
# github.com/rivo/tview v0.0.0-20200712113419-c65badfc3d92
|
||||
## explicit
|
||||
github.com/rivo/tview
|
||||
# github.com/rivo/uniseg v0.1.0
|
||||
github.com/rivo/uniseg
|
||||
|
@ -338,22 +290,19 @@ github.com/rivo/uniseg
|
|||
github.com/russross/blackfriday/v2
|
||||
# github.com/shurcooL/sanitized_anchor_name v1.0.0
|
||||
github.com/shurcooL/sanitized_anchor_name
|
||||
# github.com/stretchr/testify v1.6.0
|
||||
## explicit
|
||||
# github.com/stretchr/testify v1.6.1
|
||||
github.com/stretchr/testify/assert
|
||||
github.com/stretchr/testify/require
|
||||
# github.com/urfave/cli/v2 v2.2.0
|
||||
## explicit
|
||||
github.com/urfave/cli/v2
|
||||
github.com/urfave/cli/v2/altsrc
|
||||
# github.com/xo/dburl v0.0.0-20191005012637-293c3298d6c0
|
||||
## explicit
|
||||
github.com/xo/dburl
|
||||
# golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
||||
## explicit
|
||||
golang.org/x/crypto/blake2b
|
||||
golang.org/x/crypto/blowfish
|
||||
golang.org/x/crypto/chacha20
|
||||
golang.org/x/crypto/chacha20poly1305
|
||||
golang.org/x/crypto/curve25519
|
||||
golang.org/x/crypto/ed25519
|
||||
golang.org/x/crypto/ed25519/internal/edwards25519
|
||||
|
@ -368,7 +317,6 @@ golang.org/x/crypto/ssh
|
|||
golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
|
||||
golang.org/x/crypto/ssh/terminal
|
||||
# golang.org/x/net v0.0.0-20200904194848-62affa334b73
|
||||
## explicit
|
||||
golang.org/x/net/bpf
|
||||
golang.org/x/net/context
|
||||
golang.org/x/net/context/ctxhttp
|
||||
|
@ -386,14 +334,11 @@ golang.org/x/net/proxy
|
|||
golang.org/x/net/trace
|
||||
golang.org/x/net/websocket
|
||||
# golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
|
||||
## explicit
|
||||
golang.org/x/oauth2
|
||||
golang.org/x/oauth2/internal
|
||||
# golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
|
||||
## explicit
|
||||
golang.org/x/sync/errgroup
|
||||
# golang.org/x/sys v0.0.0-20200909081042-eff7692f9009
|
||||
## explicit
|
||||
golang.org/x/sys/cpu
|
||||
golang.org/x/sys/internal/unsafeheader
|
||||
golang.org/x/sys/unix
|
||||
|
@ -418,10 +363,8 @@ google.golang.org/appengine/internal/remote_api
|
|||
google.golang.org/appengine/internal/urlfetch
|
||||
google.golang.org/appengine/urlfetch
|
||||
# google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d
|
||||
## explicit
|
||||
google.golang.org/genproto/googleapis/rpc/status
|
||||
# google.golang.org/grpc v1.32.0
|
||||
## explicit
|
||||
google.golang.org/grpc
|
||||
google.golang.org/grpc/attributes
|
||||
google.golang.org/grpc/backoff
|
||||
|
@ -492,24 +435,17 @@ google.golang.org/protobuf/runtime/protoimpl
|
|||
google.golang.org/protobuf/types/known/anypb
|
||||
google.golang.org/protobuf/types/known/durationpb
|
||||
google.golang.org/protobuf/types/known/timestamppb
|
||||
# gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f
|
||||
## explicit
|
||||
# gopkg.in/coreos/go-oidc.v2 v2.1.0
|
||||
## explicit
|
||||
gopkg.in/coreos/go-oidc.v2
|
||||
# gopkg.in/square/go-jose.v2 v2.4.0
|
||||
## explicit
|
||||
gopkg.in/square/go-jose.v2
|
||||
gopkg.in/square/go-jose.v2/cipher
|
||||
gopkg.in/square/go-jose.v2/json
|
||||
# gopkg.in/yaml.v2 v2.3.0
|
||||
## explicit
|
||||
gopkg.in/yaml.v2
|
||||
# gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||
## explicit
|
||||
gopkg.in/yaml.v3
|
||||
# zombiezen.com/go/capnproto2 v2.18.0+incompatible
|
||||
## explicit
|
||||
zombiezen.com/go/capnproto2
|
||||
zombiezen.com/go/capnproto2/encoding/text
|
||||
zombiezen.com/go/capnproto2/internal/fulfiller
|
||||
|
|
Loading…
Reference in New Issue