update golang.org/x/crypto vendor to use acme v2 (#9056)
parent
108bed2023
commit
05f6eccf27
@ -0,0 +1,17 @@ |
||||
// 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.
|
||||
|
||||
// +build go1.11
|
||||
// +build !gccgo,!appengine
|
||||
|
||||
package chacha20 |
||||
|
||||
const bufSize = 256 |
||||
|
||||
//go:noescape
|
||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) |
||||
|
||||
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) { |
||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter) |
||||
} |
@ -0,0 +1,364 @@ |
||||
// 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 chacha20 implements the ChaCha20 and XChaCha20 encryption algorithms
|
||||
// as specified in RFC 8439 and draft-irtf-cfrg-xchacha-01.
|
||||
package chacha20 |
||||
|
||||
import ( |
||||
"crypto/cipher" |
||||
"encoding/binary" |
||||
"errors" |
||||
"math/bits" |
||||
|
||||
"golang.org/x/crypto/internal/subtle" |
||||
) |
||||
|
||||
const ( |
||||
// KeySize is the size of the key used by this cipher, in bytes.
|
||||
KeySize = 32 |
||||
|
||||
// NonceSize is the size of the nonce used with the standard variant of this
|
||||
// cipher, 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 variant of
|
||||
// this cipher, in bytes.
|
||||
NonceSizeX = 24 |
||||
) |
||||
|
||||
// Cipher is a stateful instance of ChaCha20 or XChaCha20 using a particular key
|
||||
// and nonce. A *Cipher implements the cipher.Stream interface.
|
||||
type Cipher struct { |
||||
// The ChaCha20 state is 16 words: 4 constant, 8 of key, 1 of counter
|
||||
// (incremented after each block), and 3 of nonce.
|
||||
key [8]uint32 |
||||
counter uint32 |
||||
nonce [3]uint32 |
||||
|
||||
// The last len bytes of buf are leftover key stream bytes from the previous
|
||||
// XORKeyStream invocation. The size of buf depends on how many blocks are
|
||||
// computed at a time.
|
||||
buf [bufSize]byte |
||||
len int |
||||
|
||||
// The counter-independent results of the first round are cached after they
|
||||
// are computed the first time.
|
||||
precompDone bool |
||||
p1, p5, p9, p13 uint32 |
||||
p2, p6, p10, p14 uint32 |
||||
p3, p7, p11, p15 uint32 |
||||
} |
||||
|
||||
var _ cipher.Stream = (*Cipher)(nil) |
||||
|
||||
// NewUnauthenticatedCipher creates a new ChaCha20 stream cipher with the given
|
||||
// 32 bytes key and a 12 or 24 bytes nonce. If a nonce of 24 bytes is provided,
|
||||
// the XChaCha20 construction will be used. It returns an error if key or nonce
|
||||
// have any other length.
|
||||
//
|
||||
// Note that ChaCha20, like all stream ciphers, is not authenticated and allows
|
||||
// attackers to silently tamper with the plaintext. For this reason, it is more
|
||||
// appropriate as a building block than as a standalone encryption mechanism.
|
||||
// Instead, consider using package golang.org/x/crypto/chacha20poly1305.
|
||||
func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) { |
||||
// This function is split into a wrapper so that the Cipher allocation will
|
||||
// be inlined, and depending on how the caller uses the return value, won't
|
||||
// escape to the heap.
|
||||
c := &Cipher{} |
||||
return newUnauthenticatedCipher(c, key, nonce) |
||||
} |
||||
|
||||
func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) { |
||||
if len(key) != KeySize { |
||||
return nil, errors.New("chacha20: wrong key size") |
||||
} |
||||
if len(nonce) == NonceSizeX { |
||||
// XChaCha20 uses the ChaCha20 core to mix 16 bytes of the nonce into a
|
||||
// derived key, allowing it to operate on a nonce of 24 bytes. See
|
||||
// draft-irtf-cfrg-xchacha-01, Section 2.3.
|
||||
key, _ = HChaCha20(key, nonce[0:16]) |
||||
cNonce := make([]byte, NonceSize) |
||||
copy(cNonce[4:12], nonce[16:24]) |
||||
nonce = cNonce |
||||
} else if len(nonce) != NonceSize { |
||||
return nil, errors.New("chacha20: wrong nonce size") |
||||
} |
||||
|
||||
c.key = [8]uint32{ |
||||
binary.LittleEndian.Uint32(key[0:4]), |
||||
binary.LittleEndian.Uint32(key[4:8]), |
||||
binary.LittleEndian.Uint32(key[8:12]), |
||||
binary.LittleEndian.Uint32(key[12:16]), |
||||
binary.LittleEndian.Uint32(key[16:20]), |
||||
binary.LittleEndian.Uint32(key[20:24]), |
||||
binary.LittleEndian.Uint32(key[24:28]), |
||||
binary.LittleEndian.Uint32(key[28:32]), |
||||
} |
||||
c.nonce = [3]uint32{ |
||||
binary.LittleEndian.Uint32(nonce[0:4]), |
||||
binary.LittleEndian.Uint32(nonce[4:8]), |
||||
binary.LittleEndian.Uint32(nonce[8:12]), |
||||
} |
||||
return c, nil |
||||
} |
||||
|
||||
// The constant first 4 words of the ChaCha20 state.
|
||||
const ( |
||||
j0 uint32 = 0x61707865 // expa
|
||||
j1 uint32 = 0x3320646e // nd 3
|
||||
j2 uint32 = 0x79622d32 // 2-by
|
||||
j3 uint32 = 0x6b206574 // te k
|
||||
) |
||||
|
||||
const blockSize = 64 |
||||
|
||||
// quarterRound is the core of ChaCha20. It shuffles the bits of 4 state words.
|
||||
// It's executed 4 times for each of the 20 ChaCha20 rounds, operating on all 16
|
||||
// words each round, in columnar or diagonal groups of 4 at a time.
|
||||
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) { |
||||
a += b |
||||
d ^= a |
||||
d = bits.RotateLeft32(d, 16) |
||||
c += d |
||||
b ^= c |
||||
b = bits.RotateLeft32(b, 12) |
||||
a += b |
||||
d ^= a |
||||
d = bits.RotateLeft32(d, 8) |
||||
c += d |
||||
b ^= c |
||||
b = bits.RotateLeft32(b, 7) |
||||
return a, b, c, d |
||||
} |
||||
|
||||
// XORKeyStream XORs each byte in the given slice with a byte from the
|
||||
// cipher's key stream. Dst and src must overlap entirely or not at all.
|
||||
//
|
||||
// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
|
||||
// to pass a dst bigger than src, and in that case, XORKeyStream will
|
||||
// only update dst[:len(src)] and will not touch the rest of dst.
|
||||
//
|
||||
// Multiple calls to XORKeyStream behave as if the concatenation of
|
||||
// the src buffers was passed in a single run. That is, Cipher
|
||||
// maintains state and does not reset at each XORKeyStream call.
|
||||
func (s *Cipher) XORKeyStream(dst, src []byte) { |
||||
if len(src) == 0 { |
||||
return |
||||
} |
||||
if len(dst) < len(src) { |
||||
panic("chacha20: output smaller than input") |
||||
} |
||||
dst = dst[:len(src)] |
||||
if subtle.InexactOverlap(dst, src) { |
||||
panic("chacha20: invalid buffer overlap") |
||||
} |
||||
|
||||
// First, drain any remaining key stream from a previous XORKeyStream.
|
||||
if s.len != 0 { |
||||
keyStream := s.buf[bufSize-s.len:] |
||||
if len(src) < len(keyStream) { |
||||
keyStream = keyStream[:len(src)] |
||||
} |
||||
_ = src[len(keyStream)-1] // bounds check elimination hint
|
||||
for i, b := range keyStream { |
||||
dst[i] = src[i] ^ b |
||||
} |
||||
s.len -= len(keyStream) |
||||
src = src[len(keyStream):] |
||||
dst = dst[len(keyStream):] |
||||
} |
||||
|
||||
const blocksPerBuf = bufSize / blockSize |
||||
numBufs := (uint64(len(src)) + bufSize - 1) / bufSize |
||||
if uint64(s.counter)+numBufs*blocksPerBuf >= 1<<32 { |
||||
panic("chacha20: counter overflow") |
||||
} |
||||
|
||||
// xorKeyStreamBlocks implementations expect input lengths that are a
|
||||
// multiple of bufSize. Platform-specific ones process multiple blocks at a
|
||||
// time, so have bufSizes that are a multiple of blockSize.
|
||||
|
||||
rem := len(src) % bufSize |
||||
full := len(src) - rem |
||||
|
||||
if full > 0 { |
||||
s.xorKeyStreamBlocks(dst[:full], src[:full]) |
||||
} |
||||
|
||||
// If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
|
||||
// keep the leftover keystream for the next XORKeyStream invocation.
|
||||
if rem > 0 { |
||||
s.buf = [bufSize]byte{} |
||||
copy(s.buf[:], src[full:]) |
||||
s.xorKeyStreamBlocks(s.buf[:], s.buf[:]) |
||||
s.len = bufSize - copy(dst[full:], s.buf[:]) |
||||
} |
||||
} |
||||
|
||||
func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) { |
||||
if len(dst) != len(src) || len(dst)%blockSize != 0 { |
||||
panic("chacha20: internal error: wrong dst and/or src length") |
||||
} |
||||
|
||||
// To generate each block of key stream, the initial cipher state
|
||||
// (represented below) is passed through 20 rounds of shuffling,
|
||||
// alternatively applying quarterRounds by columns (like 1, 5, 9, 13)
|
||||
// or by diagonals (like 1, 6, 11, 12).
|
||||
//
|
||||
// 0:cccccccc 1:cccccccc 2:cccccccc 3:cccccccc
|
||||
// 4:kkkkkkkk 5:kkkkkkkk 6:kkkkkkkk 7:kkkkkkkk
|
||||
// 8:kkkkkkkk 9:kkkkkkkk 10:kkkkkkkk 11:kkkkkkkk
|
||||
// 12:bbbbbbbb 13:nnnnnnnn 14:nnnnnnnn 15:nnnnnnnn
|
||||
//
|
||||
// c=constant k=key b=blockcount n=nonce
|
||||
var ( |
||||
c0, c1, c2, c3 = j0, j1, j2, j3 |
||||
c4, c5, c6, c7 = s.key[0], s.key[1], s.key[2], s.key[3] |
||||
c8, c9, c10, c11 = s.key[4], s.key[5], s.key[6], s.key[7] |
||||
_, c13, c14, c15 = s.counter, s.nonce[0], s.nonce[1], s.nonce[2] |
||||
) |
||||
|
||||
// Three quarters of the first round don't depend on the counter, so we can
|
||||
// calculate them here, and reuse them for multiple blocks in the loop, and
|
||||
// for future XORKeyStream invocations.
|
||||
if !s.precompDone { |
||||
s.p1, s.p5, s.p9, s.p13 = quarterRound(c1, c5, c9, c13) |
||||
s.p2, s.p6, s.p10, s.p14 = quarterRound(c2, c6, c10, c14) |
||||
s.p3, s.p7, s.p11, s.p15 = quarterRound(c3, c7, c11, c15) |
||||
s.precompDone = true |
||||
} |
||||
|
||||
for i := 0; i < len(src); i += blockSize { |
||||
// The remainder of the first column round.
|
||||
fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter) |
||||
|
||||
// The second diagonal round.
|
||||
x0, x5, x10, x15 := quarterRound(fcr0, s.p5, s.p10, s.p15) |
||||
x1, x6, x11, x12 := quarterRound(s.p1, s.p6, s.p11, fcr12) |
||||
x2, x7, x8, x13 := quarterRound(s.p2, s.p7, fcr8, s.p13) |
||||
x3, x4, x9, x14 := quarterRound(s.p3, fcr4, s.p9, s.p14) |
||||
|
||||
// The remaining 18 rounds.
|
||||
for i := 0; i < 9; i++ { |
||||
// Column round.
|
||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) |
||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) |
||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) |
||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) |
||||
|
||||
// Diagonal round.
|
||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) |
||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) |
||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) |
||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) |
||||
} |
||||
|
||||
// Finally, add back the initial state to generate the key stream.
|
||||
x0 += c0 |
||||
x1 += c1 |
||||
x2 += c2 |
||||
x3 += c3 |
||||
x4 += c4 |
||||
x5 += c5 |
||||
x6 += c6 |
||||
x7 += c7 |
||||
x8 += c8 |
||||
x9 += c9 |
||||
x10 += c10 |
||||
x11 += c11 |
||||
x12 += s.counter |
||||
x13 += c13 |
||||
x14 += c14 |
||||
x15 += c15 |
||||
|
||||
s.counter += 1 |
||||
if s.counter == 0 { |
||||
panic("chacha20: internal error: counter overflow") |
||||
} |
||||
|
||||
in, out := src[i:], dst[i:] |
||||
in, out = in[:blockSize], out[:blockSize] // bounds check elimination hint
|
||||
|
||||
// XOR the key stream with the source and write out the result.
|
||||
xor(out[0:], in[0:], x0) |
||||
xor(out[4:], in[4:], x1) |
||||
xor(out[8:], in[8:], x2) |
||||
xor(out[12:], in[12:], x3) |
||||
xor(out[16:], in[16:], x4) |
||||
xor(out[20:], in[20:], x5) |
||||
xor(out[24:], in[24:], x6) |
||||
xor(out[28:], in[28:], x7) |
||||
xor(out[32:], in[32:], x8) |
||||
xor(out[36:], in[36:], x9) |
||||
xor(out[40:], in[40:], x10) |
||||
xor(out[44:], in[44:], x11) |
||||
xor(out[48:], in[48:], x12) |
||||
xor(out[52:], in[52:], x13) |
||||
xor(out[56:], in[56:], x14) |
||||
xor(out[60:], in[60:], x15) |
||||
} |
||||
} |
||||
|
||||
// HChaCha20 uses the ChaCha20 core to generate a derived key from a 32 bytes
|
||||
// key and a 16 bytes nonce. It returns an error if key or nonce have any other
|
||||
// length. It is used as part of the XChaCha20 construction.
|
||||
func HChaCha20(key, nonce []byte) ([]byte, error) { |
||||
// This function is split into a wrapper so that the slice allocation will
|
||||
// be inlined, and depending on how the caller uses the return value, won't
|
||||
// escape to the heap.
|
||||
out := make([]byte, 32) |
||||
return hChaCha20(out, key, nonce) |
||||
} |
||||
|
||||
func hChaCha20(out, key, nonce []byte) ([]byte, error) { |
||||
if len(key) != KeySize { |
||||
return nil, errors.New("chacha20: wrong HChaCha20 key size") |
||||
} |
||||
if len(nonce) != 16 { |
||||
return nil, errors.New("chacha20: wrong HChaCha20 nonce size") |
||||
} |
||||
|
||||
x0, x1, x2, x3 := j0, j1, j2, j3 |
||||
x4 := binary.LittleEndian.Uint32(key[0:4]) |
||||
x5 := binary.LittleEndian.Uint32(key[4:8]) |
||||
x6 := binary.LittleEndian.Uint32(key[8:12]) |
||||
x7 := binary.LittleEndian.Uint32(key[12:16]) |
||||
x8 := binary.LittleEndian.Uint32(key[16:20]) |
||||
x9 := binary.LittleEndian.Uint32(key[20:24]) |
||||
x10 := binary.LittleEndian.Uint32(key[24:28]) |
||||
x11 := binary.LittleEndian.Uint32(key[28:32]) |
||||
x12 := binary.LittleEndian.Uint32(nonce[0:4]) |
||||
x13 := binary.LittleEndian.Uint32(nonce[4:8]) |
||||
x14 := binary.LittleEndian.Uint32(nonce[8:12]) |
||||
x15 := binary.LittleEndian.Uint32(nonce[12:16]) |
||||
|
||||
for i := 0; i < 10; i++ { |
||||
// Diagonal round.
|
||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) |
||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) |
||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) |
||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) |
||||
|
||||
// Column round.
|
||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) |
||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) |
||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) |
||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) |
||||
} |
||||
|
||||
_ = out[31] // bounds check elimination hint
|
||||
binary.LittleEndian.PutUint32(out[0:4], x0) |
||||
binary.LittleEndian.PutUint32(out[4:8], x1) |
||||
binary.LittleEndian.PutUint32(out[8:12], x2) |
||||
binary.LittleEndian.PutUint32(out[12:16], x3) |
||||
binary.LittleEndian.PutUint32(out[16:20], x12) |
||||
binary.LittleEndian.PutUint32(out[20:24], x13) |
||||
binary.LittleEndian.PutUint32(out[24:28], x14) |
||||
binary.LittleEndian.PutUint32(out[28:32], x15) |
||||
return out, nil |
||||
} |
@ -0,0 +1,13 @@ |
||||
// 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.
|
||||
|
||||
// +build !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo appengine
|
||||
|
||||
package chacha20 |
||||
|
||||
const bufSize = blockSize |
||||
|
||||
func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) { |
||||
s.xorKeyStreamBlocksGeneric(dst, src) |
||||
} |
@ -0,0 +1,16 @@ |
||||
// Copyright 2019 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,!appengine
|
||||
|
||||
package chacha20 |
||||
|
||||
const bufSize = 256 |
||||
|
||||
//go:noescape
|
||||
func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32) |
||||
|
||||
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) { |
||||
chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter) |
||||
} |
@ -0,0 +1,449 @@ |
||||
// Copyright 2019 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. |
||||
|
||||
// Based on CRYPTOGAMS code with the following comment: |
||||
// # ==================================================================== |
||||
// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
|
||||
// # project. The module is, however, dual licensed under OpenSSL and |
||||
// # CRYPTOGAMS licenses depending on where you obtain it. For further |
||||
// # details see http://www.openssl.org/~appro/cryptogams/. |
||||
// # ==================================================================== |
||||
|
||||
// Code for the perl script that generates the ppc64 assembler |
||||
// can be found in the cryptogams repository at the link below. It is based on |
||||
// the original from openssl. |
||||
|
||||
// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91 |
||||
|
||||
// The differences in this and the original implementation are |
||||
// due to the calling conventions and initialization of constants. |
||||
|
||||
// +build !gccgo,!appengine |
||||
|
||||
#include "textflag.h" |
||||
|
||||
#define OUT R3 |
||||
#define INP R4 |
||||
#define LEN R5 |
||||
#define KEY R6 |
||||
#define CNT R7 |
||||
#define TMP R15 |
||||
|
||||
#define CONSTBASE R16 |
||||
#define BLOCKS R17 |
||||
|
||||
DATA consts<>+0x00(SB)/8, $0x3320646e61707865 |
||||
DATA consts<>+0x08(SB)/8, $0x6b20657479622d32 |
||||
DATA consts<>+0x10(SB)/8, $0x0000000000000001 |
||||
DATA consts<>+0x18(SB)/8, $0x0000000000000000 |
||||
DATA consts<>+0x20(SB)/8, $0x0000000000000004 |
||||
DATA consts<>+0x28(SB)/8, $0x0000000000000000 |
||||
DATA consts<>+0x30(SB)/8, $0x0a0b08090e0f0c0d |
||||
DATA consts<>+0x38(SB)/8, $0x0203000106070405 |
||||
DATA consts<>+0x40(SB)/8, $0x090a0b080d0e0f0c |
||||
DATA consts<>+0x48(SB)/8, $0x0102030005060704 |
||||
DATA consts<>+0x50(SB)/8, $0x6170786561707865 |
||||
DATA consts<>+0x58(SB)/8, $0x6170786561707865 |
||||
DATA consts<>+0x60(SB)/8, $0x3320646e3320646e |
||||
DATA consts<>+0x68(SB)/8, $0x3320646e3320646e |
||||
DATA consts<>+0x70(SB)/8, $0x79622d3279622d32 |
||||
DATA consts<>+0x78(SB)/8, $0x79622d3279622d32 |
||||
DATA consts<>+0x80(SB)/8, $0x6b2065746b206574 |
||||
DATA consts<>+0x88(SB)/8, $0x6b2065746b206574 |
||||
DATA consts<>+0x90(SB)/8, $0x0000000100000000 |
||||
DATA consts<>+0x98(SB)/8, $0x0000000300000002 |
||||
GLOBL consts<>(SB), RODATA, $0xa0 |
||||
|
||||
//func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32) |
||||
TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 |
||||
MOVD out+0(FP), OUT |
||||
MOVD inp+8(FP), INP |
||||
MOVD len+16(FP), LEN |
||||
MOVD key+24(FP), KEY |
||||
MOVD counter+32(FP), CNT |
||||
|
||||
// Addressing for constants |
||||
MOVD $consts<>+0x00(SB), CONSTBASE |
||||
MOVD $16, R8 |
||||
MOVD $32, R9 |
||||
MOVD $48, R10 |
||||
MOVD $64, R11 |
||||
SRD $6, LEN, BLOCKS |
||||
// V16 |
||||
LXVW4X (CONSTBASE)(R0), VS48 |
||||
ADD $80,CONSTBASE |
||||
|
||||
// Load key into V17,V18 |
||||
LXVW4X (KEY)(R0), VS49 |
||||
LXVW4X (KEY)(R8), VS50 |
||||
|
||||
// Load CNT, NONCE into V19 |
||||
LXVW4X (CNT)(R0), VS51 |
||||
|
||||
// Clear V27 |
||||
VXOR V27, V27, V27 |
||||
|
||||
// V28 |
||||
LXVW4X (CONSTBASE)(R11), VS60 |
||||
|
||||
// splat slot from V19 -> V26 |
||||
VSPLTW $0, V19, V26 |
||||
|
||||
VSLDOI $4, V19, V27, V19 |
||||
VSLDOI $12, V27, V19, V19 |
||||
|
||||
VADDUWM V26, V28, V26 |
||||
|
||||
MOVD $10, R14 |
||||
MOVD R14, CTR |
||||
|
||||
loop_outer_vsx: |
||||
// V0, V1, V2, V3 |
||||
LXVW4X (R0)(CONSTBASE), VS32 |
||||
LXVW4X (R8)(CONSTBASE), VS33 |
||||
LXVW4X (R9)(CONSTBASE), VS34 |
||||
LXVW4X (R10)(CONSTBASE), VS35 |
||||
|
||||
// splat values from V17, V18 into V4-V11 |
||||
VSPLTW $0, V17, V4 |
||||
VSPLTW $1, V17, V5 |
||||
VSPLTW $2, V17, V6 |
||||
VSPLTW $3, V17, V7 |
||||
VSPLTW $0, V18, V8 |
||||
VSPLTW $1, V18, V9 |
||||
VSPLTW $2, V18, V10 |
||||
VSPLTW $3, V18, V11 |
||||
|
||||
// VOR |
||||
VOR V26, V26, V12 |
||||
|
||||
// splat values from V19 -> V13, V14, V15 |
||||
VSPLTW $1, V19, V13 |
||||
VSPLTW $2, V19, V14 |
||||
VSPLTW $3, V19, V15 |
||||
|
||||
// splat const values |
||||
VSPLTISW $-16, V27 |
||||
VSPLTISW $12, V28 |
||||
VSPLTISW $8, V29 |
||||
VSPLTISW $7, V30 |
||||
|
||||
loop_vsx: |
||||
VADDUWM V0, V4, V0 |
||||
VADDUWM V1, V5, V1 |
||||
VADDUWM V2, V6, V2 |
||||
VADDUWM V3, V7, V3 |
||||
|
||||
VXOR V12, V0, V12 |
||||
VXOR V13, V1, V13 |
||||
VXOR V14, V2, V14 |
||||
VXOR V15, V3, V15 |
||||
|
||||
VRLW V12, V27, V12 |
||||
VRLW V13, V27, V13 |
||||
VRLW V14, V27, V14 |
||||
VRLW V15, V27, V15 |
||||
|
||||
VADDUWM V8, V12, V8 |
||||
VADDUWM V9, V13, V9 |
||||
VADDUWM V10, V14, V10 |
||||
VADDUWM V11, V15, V11 |
||||
|
||||
VXOR V4, V8, V4 |
||||
VXOR V5, V9, V5 |
||||
VXOR V6, V10, V6 |
||||
VXOR V7, V11, V7 |
||||
|
||||
VRLW V4, V28, V4 |
||||
VRLW V5, V28, V5 |
||||
VRLW V6, V28, V6 |
||||
VRLW V7, V28, V7 |
||||
|
||||
VADDUWM V0, V4, V0 |
||||
VADDUWM V1, V5, V1 |
||||
VADDUWM V2, V6, V2 |
||||
VADDUWM V3, V7, V3 |
||||
|
||||
VXOR V12, V0, V12 |
||||
VXOR V13, V1, V13 |
||||
VXOR V14, V2, V14 |
||||
VXOR V15, V3, V15 |
||||
|
||||
VRLW V12, V29, V12 |
||||
VRLW V13, V29, V13 |
||||
VRLW V14, V29, V14 |
||||
VRLW V15, V29, V15 |
||||
|
||||
VADDUWM V8, V12, V8 |
||||
VADDUWM V9, V13, V9 |
||||
VADDUWM V10, V14, V10 |
||||
VADDUWM V11, V15, V11 |
||||
|
||||
VXOR V4, V8, V4 |
||||
VXOR V5, V9, V5 |
||||
VXOR V6, V10, V6 |
||||
VXOR V7, V11, V7 |
||||
|
||||
VRLW V4, V30, V4 |
||||
VRLW V5, V30, V5 |
||||
VRLW V6, V30, V6 |
||||
VRLW V7, V30, V7 |
||||
|
||||
VADDUWM V0, V5, V0 |
||||
VADDUWM V1, V6, V1 |
||||
VADDUWM V2, V7, V2 |
||||
VADDUWM V3, V4, V3 |
||||
|
||||
VXOR V15, V0, V15 |
||||
VXOR V12, V1, V12 |
||||
VXOR V13, V2, V13 |
||||
VXOR V14, V3, V14 |
||||
|
||||
VRLW V15, V27, V15 |
||||
VRLW V12, V27, V12 |
||||
VRLW V13, V27, V13 |
||||
VRLW V14, V27, V14 |
||||
|
||||
VADDUWM V10, V15, V10 |
||||
VADDUWM V11, V12, V11 |
||||
VADDUWM V8, V13, V8 |
||||
VADDUWM V9, V14, V9 |
||||
|
||||
VXOR V5, V10, V5 |
||||
VXOR V6, V11, V6 |
||||
VXOR V7, V8, V7 |
||||
VXOR V4, V9, V4 |
||||
|
||||
VRLW V5, V28, V5 |
||||
VRLW V6, V28, V6 |
||||
VRLW V7, V28, V7 |
||||
VRLW V4, V28, V4 |
||||
|
||||
VADDUWM V0, V5, V0 |
||||
VADDUWM V1, V6, V1 |
||||
VADDUWM V2, V7, V2 |
||||
VADDUWM V3, V4, V3 |
||||
|
||||
VXOR V15, V0, V15 |
||||
VXOR V12, V1, V12 |
||||
VXOR V13, V2, V13 |
||||
VXOR V14, V3, V14 |
||||
|
||||
VRLW V15, V29, V15 |
||||
VRLW V12, V29, V12 |
||||
VRLW V13, V29, V13 |
||||
VRLW V14, V29, V14 |
||||
|
||||
VADDUWM V10, V15, V10 |
||||
VADDUWM V11, V12, V11 |
||||
VADDUWM V8, V13, V8 |
||||
VADDUWM V9, V14, V9 |
||||
|
||||
VXOR V5, V10, V5 |
||||
VXOR V6, V11, V6 |
||||
VXOR V7, V8, V7 |
||||
VXOR V4, V9, V4 |
||||
|
||||
VRLW V5, V30, V5 |
||||
VRLW V6, V30, V6 |
||||
VRLW V7, V30, V7 |
||||
VRLW V4, V30, V4 |
||||
BC 16, LT, loop_vsx |
||||
|
||||
VADDUWM V12, V26, V12 |
||||
|
||||
WORD $0x13600F8C // VMRGEW V0, V1, V27 |
||||
WORD $0x13821F8C // VMRGEW V2, V3, V28 |
||||
|
||||
WORD $0x10000E8C // VMRGOW V0, V1, V0 |
||||
WORD $0x10421E8C // VMRGOW V2, V3, V2 |
||||
|
||||
WORD $0x13A42F8C // VMRGEW V4, V5, V29 |
||||
WORD $0x13C63F8C // VMRGEW V6, V7, V30 |
||||
|
||||
XXPERMDI VS32, VS34, $0, VS33 |
||||
XXPERMDI VS32, VS34, $3, VS35 |
||||
XXPERMDI VS59, VS60, $0, VS32 |
||||
XXPERMDI VS59, VS60, $3, VS34 |
||||
|
||||
WORD $0x10842E8C // VMRGOW V4, V5, V4 |
||||
WORD $0x10C63E8C // VMRGOW V6, V7, V6 |
||||
|
||||
WORD $0x13684F8C // VMRGEW V8, V9, V27 |
||||
WORD $0x138A5F8C // VMRGEW V10, V11, V28 |
||||
|
||||
XXPERMDI VS36, VS38, $0, VS37 |
||||
XXPERMDI VS36, VS38, $3, VS39 |
||||
XXPERMDI VS61, VS62, $0, VS36 |
||||
XXPERMDI VS61, VS62, $3, VS38 |
||||
|
||||
WORD $0x11084E8C // VMRGOW V8, V9, V8 |
||||
WORD $0x114A5E8C // VMRGOW V10, V11, V10 |
||||
|
||||
WORD $0x13AC6F8C // VMRGEW V12, V13, V29 |
||||
WORD $0x13CE7F8C // VMRGEW V14, V15, V30 |
||||
|
||||
XXPERMDI VS40, VS42, $0, VS41 |
||||
XXPERMDI VS40, VS42, $3, VS43 |
||||
XXPERMDI VS59, VS60, $0, VS40 |
||||
XXPERMDI VS59, VS60, $3, VS42 |
||||
|
||||
WORD $0x118C6E8C // VMRGOW V12, V13, V12 |
||||
WORD $0x11CE7E8C // VMRGOW V14, V15, V14 |
||||
|
||||
VSPLTISW $4, V27 |
||||
VADDUWM V26, V27, V26 |
||||
|
||||
XXPERMDI VS44, VS46, $0, VS45 |
||||
XXPERMDI VS44, VS46, $3, VS47 |
||||
XXPERMDI VS61, VS62, $0, VS44 |
||||
XXPERMDI VS61, VS62, $3, VS46 |
||||
|
||||
VADDUWM V0, V16, V0 |
||||
VADDUWM V4, V17, V4 |
||||
VADDUWM V8, V18, V8 |
||||
VADDUWM V12, V19, V12 |
||||
|
||||
CMPU LEN, $64 |
||||
BLT tail_vsx |
||||
|
||||
// Bottom of loop |
||||
LXVW4X (INP)(R0), VS59 |
||||
LXVW4X (INP)(R8), VS60 |
||||
LXVW4X (INP)(R9), VS61 |
||||
LXVW4X (INP)(R10), VS62 |
||||
|
||||
VXOR V27, V0, V27 |
||||
VXOR V28, V4, V28 |
||||
VXOR V29, V8, V29 |
||||
VXOR V30, V12, V30 |
||||
|
||||
STXVW4X VS59, (OUT)(R0) |
||||
STXVW4X VS60, (OUT)(R8) |
||||
ADD $64, INP |
||||
STXVW4X VS61, (OUT)(R9) |
||||
ADD $-64, LEN |
||||
STXVW4X VS62, (OUT)(R10) |
||||
ADD $64, OUT |
||||
BEQ done_vsx |
||||
|
||||
VADDUWM V1, V16, V0 |
||||
VADDUWM V5, V17, V4 |
||||
VADDUWM V9, V18, V8 |
||||
VADDUWM V13, V19, V12 |
||||
|
||||
CMPU LEN, $64 |
||||
BLT tail_vsx |
||||
|
||||
LXVW4X (INP)(R0), VS59 |
||||
LXVW4X (INP)(R8), VS60 |
||||
LXVW4X (INP)(R9), VS61 |
||||
LXVW4X (INP)(R10), VS62 |
||||
VXOR V27, V0, V27 |
||||
|
||||
VXOR V28, V4, V28 |
||||
VXOR V29, V8, V29 |
||||
VXOR V30, V12, V30 |
||||
|
||||
STXVW4X VS59, (OUT)(R0) |
||||
STXVW4X VS60, (OUT)(R8) |
||||
ADD $64, INP |
||||
STXVW4X VS61, (OUT)(R9) |
||||
ADD $-64, LEN |
||||
STXVW4X VS62, (OUT)(V10) |
||||
ADD $64, OUT |
||||
BEQ done_vsx |
||||
|
||||
VADDUWM V2, V16, V0 |
||||
VADDUWM V6, V17, V4 |
||||
VADDUWM V10, V18, V8 |
||||
VADDUWM V14, V19, V12 |
||||
|
||||
CMPU LEN, $64 |
||||
BLT tail_vsx |
||||
|
||||
LXVW4X (INP)(R0), VS59 |
||||
LXVW4X (INP)(R8), VS60 |
||||
LXVW4X (INP)(R9), VS61 |
||||
LXVW4X (INP)(R10), VS62 |
||||
|
||||
VXOR V27, V0, V27 |
||||
VXOR V28, V4, V28 |
||||
VXOR V29, V8, V29 |
||||
VXOR V30, V12, V30 |
||||
|
||||
STXVW4X VS59, (OUT)(R0) |
||||
STXVW4X VS60, (OUT)(R8) |
||||
ADD $64, INP |
||||
STXVW4X VS61, (OUT)(R9) |
||||
ADD $-64, LEN |
||||
STXVW4X VS62, (OUT)(R10) |
||||
ADD $64, OUT |
||||
BEQ done_vsx |
||||
|
||||
VADDUWM V3, V16, V0 |
||||
VADDUWM V7, V17, V4 |
||||
VADDUWM V11, V18, V8 |
||||
VADDUWM V15, V19, V12 |
||||
|
||||
CMPU LEN, $64 |
||||
BLT tail_vsx |
||||
|
||||
LXVW4X (INP)(R0), VS59 |
||||
LXVW4X (INP)(R8), VS60 |
||||
LXVW4X (INP)(R9), VS61 |
||||
LXVW4X (INP)(R10), VS62 |
||||
|
||||
VXOR V27, V0, V27 |
||||
VXOR V28, V4, V28 |
||||
VXOR V29, V8, V29 |
||||
VXOR V30, V12, V30 |
||||
|
||||
STXVW4X VS59, (OUT)(R0) |
||||
STXVW4X VS60, (OUT)(R8) |
||||
ADD $64, INP |
||||
STXVW4X VS61, (OUT)(R9) |
||||
ADD $-64, LEN |
||||
STXVW4X VS62, (OUT)(R10) |
||||
ADD $64, OUT |
||||
|
||||
MOVD $10, R14 |
||||
MOVD R14, CTR |
||||
BNE loop_outer_vsx |
||||
|
||||
done_vsx: |
||||
// Increment counter by number of 64 byte blocks |
||||
MOVD (CNT), R14 |
||||
ADD BLOCKS, R14 |
||||
MOVD R14, (CNT) |
||||
RET |
||||
|
||||
tail_vsx: |
||||
ADD $32, R1, R11 |
||||
MOVD LEN, CTR |
||||
|
||||
// Save values on stack to copy from |
||||
STXVW4X VS32, (R11)(R0) |
||||
STXVW4X VS36, (R11)(R8) |
||||
STXVW4X VS40, (R11)(R9) |
||||
STXVW4X VS44, (R11)(R10) |
||||
ADD $-1, R11, R12 |
||||
ADD $-1, INP |
||||
ADD $-1, OUT |
||||
|
||||
looptail_vsx: |
||||
// Copying the result to OUT |
||||
// in bytes. |
||||
MOVBZU 1(R12), KEY |
||||
MOVBZU 1(INP), TMP |
||||
XOR KEY, TMP, KEY |
||||
MOVBU KEY, 1(OUT) |
||||
BC 16, LT, looptail_vsx |
||||
|
||||
// Clear the stack values |
||||
STXVW4X VS48, (R11)(R0) |
||||
STXVW4X VS48, (R11)(R8) |
||||
STXVW4X VS48, (R11)(R9) |
||||
STXVW4X VS48, (R11)(R10) |
||||
BR done_vsx |
@ -0,0 +1,26 @@ |
||||
// 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.
|
||||
|
||||
// +build !gccgo,!appengine
|
||||
|
||||
package chacha20 |
||||
|
||||
import "golang.org/x/sys/cpu" |
||||
|
||||
var haveAsm = cpu.S390X.HasVX |
||||
|
||||
const bufSize = 256 |
||||
|
||||
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
|
||||
// be called when the vector facility is available. Implementation in asm_s390x.s.
|
||||
//go:noescape
|
||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) |
||||
|
||||
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) { |
||||
if cpu.S390X.HasVX { |
||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter) |
||||
} else { |
||||
c.xorKeyStreamBlocksGeneric(dst, src) |
||||
} |
||||
} |
@ -1,8 +0,0 @@ |
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
||||
|
||||
#define REDMASK51 0x0007FFFFFFFFFFFF |
@ -1,20 +0,0 @@ |
||||
// Copyright 2012 The Go Authors. All rights reserved. |
||||
// Use of this source code is governed by a BSD-style |
||||
// license that can be found in the LICENSE file. |
||||
|
||||
// This code was translated into a form compatible with 6a from the public |
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html |
||||
|
||||
// +build amd64,!gccgo,!appengine |
||||
|
||||
// These constants cannot be encoded in non-MOVQ immediates. |
||||
// We access them directly from memory instead. |
||||
|
||||
DATA ·_121666_213(SB)/8, $996687872 |
||||
GLOBL ·_121666_213(SB), 8, $8 |
||||
|
||||
DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA |
||||
GLOBL ·_2P0(SB), 8, $8 |
||||
|
||||
DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE |
||||
GLOBL ·_2P1234(SB), 8, $8 |
@ -1,65 +0,0 @@ |
||||
// Copyright 2012 The Go Authors. All rights reserved. |
||||
// Use of this source code is governed by a BSD-style |
||||
// license that can be found in the LICENSE file. |
||||
|
||||
// +build amd64,!gccgo,!appengine |
||||
|
||||
// func cswap(inout *[4][5]uint64, v uint64) |
||||
TEXT ·cswap(SB),7,$0 |
||||
MOVQ inout+0(FP),DI |
||||
MOVQ v+8(FP),SI |
||||
|
||||
SUBQ $1, SI |
||||
NOTQ SI |
||||
MOVQ SI, X15 |
||||
PSHUFD $0x44, X15, X15 |
||||
|
||||
MOVOU 0(DI), X0 |
||||
MOVOU 16(DI), X2 |
||||
MOVOU 32(DI), X4 |
||||
MOVOU 48(DI), X6 |
||||
MOVOU 64(DI), X8 |
||||
MOVOU 80(DI), X1 |
||||
MOVOU 96(DI), X3 |
||||
MOVOU 112(DI), X5 |
||||
MOVOU 128(DI), X7 |
||||
MOVOU 144(DI), X9 |
||||
|
||||
MOVO X1, X10 |
||||
MOVO X3, X11 |
||||
MOVO X5, X12 |
||||
MOVO X7, X13 |
||||
MOVO X9, X14 |
||||
|
||||
PXOR X0, X10 |
||||
PXOR X2, X11 |
||||
PXOR X4, X12 |
||||
PXOR X6, X13 |
||||
PXOR X8, X14 |
||||
PAND X15, X10 |
||||
PAND X15, X11 |
||||
PAND X15, X12 |
||||
PAND X15, X13 |
||||
PAND X15, X14 |
||||
PXOR X10, X0 |
||||
PXOR X10, X1 |
||||
PXOR X11, X2 |
||||
PXOR X11, X3 |
||||
PXOR X12, X4 |
||||
PXOR X12, X5 |
||||
PXOR X13, X6 |
||||
PXOR X13, X7 |
||||
PXOR X14, X8 |
||||
PXOR X14, X9 |
||||
|
||||
MOVOU X0, 0(DI) |
||||
MOVOU X2, 16(DI) |
||||
MOVOU X4, 32(DI) |
||||
MOVOU X6, 48(DI) |
||||
MOVOU X8, 64(DI) |
||||
MOVOU X1, 80(DI) |
||||
MOVOU X3, 96(DI) |
||||
MOVOU X5, 112(DI) |
||||
MOVOU X7, 128(DI) |
||||
MOVOU X9, 144(DI) |
||||
RET |
@ -1,834 +1,95 @@ |
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Copyright 2019 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.
|
||||
|
||||
// We have an implementation in amd64 assembly so this code is only run on
|
||||
// non-amd64 platforms. The amd64 assembly does not support gccgo.
|
||||
// +build !amd64 gccgo appengine
|
||||
|
||||
package curve25519 |
||||
// Package curve25519 provides an implementation of the X25519 function, which
|
||||
// performs scalar multiplication on the elliptic curve known as Curve25519.
|
||||
// See RFC 7748.
|
||||
package curve25519 // import "golang.org/x/crypto/curve25519"
|
||||
|
||||
import ( |
||||
"encoding/binary" |
||||
"crypto/subtle" |
||||
"fmt" |
||||
) |
||||
|
||||
// This code is a port of the public domain, "ref10" implementation of
|
||||
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
|
||||
|
||||
// fieldElement represents an element of the field GF(2^255 - 19). An element
|
||||
// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
|
||||
// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
|
||||
// context.
|
||||
type fieldElement [10]int32 |
||||
|
||||
func feZero(fe *fieldElement) { |
||||
for i := range fe { |
||||
fe[i] = 0 |
||||
} |
||||
} |
||||
|
||||
func feOne(fe *fieldElement) { |
||||
feZero(fe) |
||||
fe[0] = 1 |
||||
} |
||||
|
||||
func feAdd(dst, a, b *fieldElement) { |
||||
for i := range dst { |
||||
dst[i] = a[i] + b[i] |
||||
} |
||||
} |
||||
|
||||
func feSub(dst, a, b *fieldElement) { |
||||
for i := range dst { |
||||
dst[i] = a[i] - b[i] |
||||
} |
||||
} |
||||
|
||||
func feCopy(dst, src *fieldElement) { |
||||
for i := range dst { |
||||
dst[i] = src[i] |
||||
} |
||||
} |
||||
|
||||
// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
|
||||
// ScalarMult sets dst to the product scalar * point.
|
||||
//
|
||||
// Preconditions: b in {0,1}.
|
||||
func feCSwap(f, g *fieldElement, b int32) { |
||||
b = -b |
||||
for i := range f { |
||||
t := b & (f[i] ^ g[i]) |
||||
f[i] ^= t |
||||
g[i] ^= t |
||||
} |
||||
// Deprecated: when provided a low-order point, ScalarMult will set dst to all
|
||||
// zeroes, irrespective of the scalar. Instead, use the X25519 function, which
|
||||
// will return an error.
|
||||
func ScalarMult(dst, scalar, point *[32]byte) { |
||||
scalarMult(dst, scalar, point) |
||||
} |
||||
|
||||
// load3 reads a 24-bit, little-endian value from in.
|
||||
func load3(in []byte) int64 { |
||||
var r int64 |
||||
r = int64(in[0]) |
||||
r |= int64(in[1]) << 8 |
||||
r |= int64(in[2]) << 16 |
||||
return r |
||||
} |
||||
|
||||
// load4 reads a 32-bit, little-endian value from in.
|
||||
func load4(in []byte) int64 { |
||||
return int64(binary.LittleEndian.Uint32(in)) |
||||
} |
||||
|
||||
func feFromBytes(dst *fieldElement, src *[32]byte) { |
||||
h0 := load4(src[:]) |
||||
h1 := load3(src[4:]) << 6 |
||||
h2 := load3(src[7:]) << 5 |
||||
h3 := load3(src[10:]) << 3 |
||||
h4 := load3(src[13:]) << 2 |
||||
h5 := load4(src[16:]) |
||||
h6 := load3(src[20:]) << 7 |
||||
h7 := load3(src[23:]) << 5 |
||||
h8 := load3(src[26:]) << 4 |
||||
h9 := (load3(src[29:]) & 0x7fffff) << 2 |
||||
|
||||
var carry [10]int64 |
||||
carry[9] = (h9 + 1<<24) >> 25 |
||||
h0 += carry[9] * 19 |
||||
h9 -= carry[9] << 25 |
||||
carry[1] = (h1 + 1<<24) >> 25 |
||||
h2 += carry[1] |
||||
h1 -= carry[1] << 25 |
||||
carry[3] = (h3 + 1<<24) >> 25 |
||||
h4 += carry[3] |
||||
h3 -= carry[3] << 25 |
||||
carry[5] = (h5 + 1<<24) >> 25 |
||||
h6 += carry[5] |
||||
h5 -= carry[5] << 25 |
||||
carry[7] = (h7 + 1<<24) >> 25 |
||||
h8 += carry[7] |
||||
h7 -= carry[7] << 25 |
||||
|
||||
carry[0] = (h0 + 1<<25) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
carry[2] = (h2 + 1<<25) >> 26 |
||||
h3 += carry[2] |
||||
h2 -= carry[2] << 26 |
||||
carry[4] = (h4 + 1<<25) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
carry[6] = (h6 + 1<<25) >> 26 |
||||
h7 += carry[6] |
||||
h6 -= carry[6] << 26 |
||||
carry[8] = (h8 + 1<<25) >> 26 |
||||
h9 += carry[8] |
||||
h8 -= carry[8] << 26 |
||||
|
||||
dst[0] = int32(h0) |
||||
dst[1] = int32(h1) |
||||
dst[2] = int32(h2) |
||||
dst[3] = int32(h3) |
||||
dst[4] = int32(h4) |
||||
dst[5] = int32(h5) |
||||
dst[6] = int32(h6) |
||||
dst[7] = int32(h7) |
||||
dst[8] = int32(h8) |
||||
dst[9] = int32(h9) |
||||
} |
||||
|
||||
// feToBytes marshals h to s.
|
||||
// Preconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
//
|
||||
// Write p=2^255-19; q=floor(h/p).
|
||||
// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
|
||||
//
|
||||
// Proof:
|
||||
// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
|
||||
// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
|
||||
//
|
||||
// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
|
||||
// Then 0<y<1.
|
||||
//
|
||||
// Write r=h-pq.
|
||||
// Have 0<=r<=p-1=2^255-20.
|
||||
// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
|
||||
// ScalarBaseMult sets dst to the product scalar * base where base is the
|
||||
// standard generator.
|
||||
//
|
||||
// Write x=r+19(2^-255)r+y.
|
||||
// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
|
||||
//
|
||||
// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
|
||||
// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
|
||||
func feToBytes(s *[32]byte, h *fieldElement) { |
||||
var carry [10]int32 |
||||
|
||||
q := (19*h[9] + (1 << 24)) >> 25 |
||||
q = (h[0] + q) >> 26 |
||||
q = (h[1] + q) >> 25 |
||||
q = (h[2] + q) >> 26 |
||||
q = (h[3] + q) >> 25 |
||||
q = (h[4] + q) >> 26 |
||||
q = (h[5] + q) >> 25 |
||||
q = (h[6] + q) >> 26 |
||||
q = (h[7] + q) >> 25 |
||||
q = (h[8] + q) >> 26 |
||||
q = (h[9] + q) >> 25 |
||||
|
||||
// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
|
||||
h[0] += 19 * q |
||||
// Goal: Output h-2^255 q, which is between 0 and 2^255-20.
|
||||
|
||||
carry[0] = h[0] >> 26 |
||||
h[1] += carry[0] |
||||
h[0] -= carry[0] << 26 |
||||
carry[1] = h[1] >> 25 |
||||
h[2] += carry[1] |
||||
h[1] -= carry[1] << 25 |
||||
carry[2] = h[2] >> 26 |
||||
h[3] += carry[2] |
||||
h[2] -= carry[2] << 26 |
||||
carry[3] = h[3] >> 25 |
||||
h[4] += carry[3] |
||||
h[3] -= carry[3] << 25 |
||||
carry[4] = h[4] >> 26 |
||||
h[5] += carry[4] |
||||
h[4] -= carry[4] << 26 |
||||
carry[5] = h[5] >> 25 |
||||
h[6] += carry[5] |
||||
h[5] -= carry[5] << 25 |
||||
carry[6] = h[6] >> 26 |
||||
h[7] += carry[6] |
||||
h[6] -= carry[6] << 26 |
||||
carry[7] = h[7] >> 25 |
||||
h[8] += carry[7] |
||||
h[7] -= carry[7] << 25 |
||||
carry[8] = h[8] >> 26 |
||||
h[9] += carry[8] |
||||
h[8] -= carry[8] << 26 |
||||
carry[9] = h[9] >> 25 |
||||
h[9] -= carry[9] << 25 |
||||
// h10 = carry9
|
||||
|
||||
// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
|
||||
// Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
|
||||
// evidently 2^255 h10-2^255 q = 0.
|
||||
// Goal: Output h[0]+...+2^230 h[9].
|
||||
|
||||
s[0] = byte(h[0] >> 0) |
||||
s[1] = byte(h[0] >> 8) |
||||
s[2] = byte(h[0] >> 16) |
||||
s[3] = byte((h[0] >> 24) | (h[1] << 2)) |
||||
s[4] = byte(h[1] >> 6) |
||||
s[5] = byte(h[1] >> 14) |
||||
s[6] = byte((h[1] >> 22) | (h[2] << 3)) |
||||
s[7] = byte(h[2] >> 5) |
||||
s[8] = byte(h[2] >> 13) |
||||
s[9] = byte((h[2] >> 21) | (h[3] << 5)) |
||||
s[10] = byte(h[3] >> 3) |
||||
s[11] = byte(h[3] >> 11) |
||||
s[12] = byte((h[3] >> 19) | (h[4] << 6)) |
||||
s[13] = byte(h[4] >> 2) |
||||
s[14] = byte(h[4] >> 10) |
||||
s[15] = byte(h[4] >> 18) |
||||
s[16] = byte(h[5] >> 0) |
||||
s[17] = byte(h[5] >> 8) |
||||
s[18] = byte(h[5] >> 16) |
||||
s[19] = byte((h[5] >> 24) | (h[6] << 1)) |
||||
s[20] = byte(h[6] >> 7) |
||||
s[21] = byte(h[6] >> 15) |
||||
s[22] = byte((h[6] >> 23) | (h[7] << 3)) |
||||
s[23] = byte(h[7] >> 5) |
||||
s[24] = byte(h[7] >> 13) |
||||
s[25] = byte((h[7] >> 21) | (h[8] << 4)) |
||||
s[26] = byte(h[8] >> 4) |
||||
s[27] = byte(h[8] >> 12) |
||||
s[28] = byte((h[8] >> 20) | (h[9] << 6)) |
||||
s[29] = byte(h[9] >> 2) |
||||
s[30] = byte(h[9] >> 10) |
||||
s[31] = byte(h[9] >> 18) |
||||
// It is recommended to use the X25519 function with Basepoint instead, as
|
||||
// copying into fixed size arrays can lead to unexpected bugs.
|
||||
func ScalarBaseMult(dst, scalar *[32]byte) { |
||||
ScalarMult(dst, scalar, &basePoint) |
||||
} |
||||
|
||||
// feMul calculates h = f * g
|
||||
// Can overlap h with f or g.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
//
|
||||
// Notes on implementation strategy:
|
||||
//
|
||||
// Using schoolbook multiplication.
|
||||
// Karatsuba would save a little in some cost models.
|
||||
//
|
||||
// Most multiplications by 2 and 19 are 32-bit precomputations;
|
||||
// cheaper than 64-bit postcomputations.
|
||||
//
|
||||
// There is one remaining multiplication by 19 in the carry chain;
|
||||
// one *19 precomputation can be merged into this,
|
||||
// but the resulting data flow is considerably less clean.
|
||||
//
|
||||
// There are 12 carries below.
|
||||
// 10 of them are 2-way parallelizable and vectorizable.
|
||||
// Can get away with 11 carries, but then data flow is much deeper.
|
||||
//
|
||||
// With tighter constraints on inputs can squeeze carries into int32.
|
||||
func feMul(h, f, g *fieldElement) { |
||||
f0 := f[0] |
||||
f1 := f[1] |
||||
f2 := f[2] |
||||
f3 := f[3] |
||||
f4 := f[4] |
||||
f5 := f[5] |
||||
f6 := f[6] |
||||
f7 := f[7] |
||||
f8 := f[8] |
||||
f9 := f[9] |
||||
g0 := g[0] |
||||
g1 := g[1] |
||||
g2 := g[2] |
||||
g3 := g[3] |
||||
g4 := g[4] |
||||
g5 := g[5] |
||||
g6 := g[6] |
||||
g7 := g[7] |
||||
g8 := g[8] |
||||
g9 := g[9] |
||||
g1_19 := 19 * g1 // 1.4*2^29
|
||||
g2_19 := 19 * g2 // 1.4*2^30; still ok
|
||||
g3_19 := 19 * g3 |
||||
g4_19 := 19 * g4 |
||||
g5_19 := 19 * g5 |
||||
g6_19 := 19 * g6 |
||||
g7_19 := 19 * g7 |
||||
g8_19 := 19 * g8 |
||||
g9_19 := 19 * g9 |
||||
f1_2 := 2 * f1 |
||||
f3_2 := 2 * f3 |
||||
f5_2 := 2 * f5 |
||||
f7_2 := 2 * f7 |
||||
f9_2 := 2 * f9 |
||||
f0g0 := int64(f0) * int64(g0) |
||||
f0g1 := int64(f0) * int64(g1) |
||||
f0g2 := int64(f0) * int64(g2) |
||||
f0g3 := int64(f0) * int64(g3) |
||||
f0g4 := int64(f0) * int64(g4) |
||||
f0g5 := int64(f0) * int64(g5) |
||||
f0g6 := int64(f0) * int64(g6) |
||||
f0g7 := int64(f0) * int64(g7) |
||||
f0g8 := int64(f0) * int64(g8) |
||||
f0g9 := int64(f0) * int64(g9) |
||||
f1g0 := int64(f1) * int64(g0) |
||||
f1g1_2 := int64(f1_2) * int64(g1) |
||||
f1g2 := int64(f1) * int64(g2) |
||||
f1g3_2 := int64(f1_2) * int64(g3) |
||||
f1g4 := int64(f1) * int64(g4) |
||||
f1g5_2 := int64(f1_2) * int64(g5) |
||||
f1g6 := int64(f1) * int64(g6) |
||||
f1g7_2 := int64(f1_2) * int64(g7) |
||||
f1g8 := int64(f1) * int64(g8) |
||||
f1g9_38 := int64(f1_2) * int64(g9_19) |
||||
f2g0 := int64(f2) * int64(g0) |
||||
f2g1 := int64(f2) * int64(g1) |
||||
f2g2 := int64(f2) * int64(g2) |
||||
f2g3 := int64(f2) * int64(g3) |
||||
f2g4 := int64(f2) * int64(g4) |
||||
f2g5 := int64(f2) * int64(g5) |
||||
f2g6 := int64(f2) * int64(g6) |
||||
f2g7 := int64(f2) * int64(g7) |
||||
f2g8_19 := int64(f2) * int64(g8_19) |
||||
f2g9_19 := int64(f2) * int64(g9_19) |
||||
f3g0 := int64(f3) * int64(g0) |
||||
f3g1_2 := int64(f3_2) * int64(g1) |
||||
f3g2 := int64(f3) * int64(g2) |
||||
f3g3_2 := int64(f3_2) * int64(g3) |
||||
f3g4 := int64(f3) * int64(g4) |
||||
f3g5_2 := int64(f3_2) * int64(g5) |
||||
f3g6 := int64(f3) * int64(g6) |
||||
f3g7_38 := int64(f3_2) * int64(g7_19) |
||||
f3g8_19 := int64(f3) * int64(g8_19) |
||||
f3g9_38 := int64(f3_2) * int64(g9_19) |
||||
f4g0 := int64(f4) * int64(g0) |
||||
f4g1 := int64(f4) * int64(g1) |
||||
f4g2 := int64(f4) * int64(g2) |
||||
f4g3 := int64(f4) * int64(g3) |
||||
f4g4 := int64(f4) * int64(g4) |
||||
f4g5 := int64(f4) * int64(g5) |
||||
f4g6_19 := int64(f4) * int64(g6_19) |
||||
f4g7_19 := int64(f4) * int64(g7_19) |
||||
f4g8_19 := int64(f4) * int64(g8_19) |
||||
f4g9_19 := int64(f4) * int64(g9_19) |
||||
f5g0 := int64(f5) * int64(g0) |
||||
f5g1_2 := int64(f5_2) * int64(g1) |
||||
f5g2 := int64(f5) * int64(g2) |
||||
f5g3_2 := int64(f5_2) * int64(g3) |
||||
f5g4 := int64(f5) * int64(g4) |
||||
f5g5_38 := int64(f5_2) * int64(g5_19) |
||||
f5g6_19 := int64(f5) * int64(g6_19) |
||||
f5g7_38 := int64(f5_2) * int64(g7_19) |
||||
f5g8_19 := int64(f5) * int64(g8_19) |
||||
f5g9_38 := int64(f5_2) * int64(g9_19) |
||||
f6g0 := int64(f6) * int64(g0) |
||||
f6g1 := int64(f6) * int64(g1) |
||||
f6g2 := int64(f6) * int64(g2) |
||||
f6g3 := int64(f6) * int64(g3) |
||||
f6g4_19 := int64(f6) * int64(g4_19) |
||||
f6g5_19 := int64(f6) * int64(g5_19) |
||||
f6g6_19 := int64(f6) * int64(g6_19) |
||||
f6g7_19 := int64(f6) * int64(g7_19) |
||||
f6g8_19 := int64(f6) * int64(g8_19) |
||||
f6g9_19 := int64(f6) * int64(g9_19) |
||||
f7g0 := int64(f7) * int64(g0) |
||||
f7g1_2 := int64(f7_2) * int64(g1) |
||||
f7g2 := int64(f7) * int64(g2) |
||||
f7g3_38 := int64(f7_2) * int64(g3_19) |
||||
f7g4_19 := int64(f7) * int64(g4_19) |
||||
f7g5_38 := int64(f7_2) * int64(g5_19) |
||||
f7g6_19 := int64(f7) * int64(g6_19) |
||||
f7g7_38 := int64(f7_2) * int64(g7_19) |
||||
f7g8_19 := int64(f7) * int64(g8_19) |
||||
f7g9_38 := int64(f7_2) * int64(g9_19) |
||||
f8g0 := int64(f8) * int64(g0) |
||||
f8g1 := int64(f8) * int64(g1) |
||||
f8g2_19 := int64(f8) * int64(g2_19) |
||||
f8g3_19 := int64(f8) * int64(g3_19) |
||||
f8g4_19 := int64(f8) * int64(g4_19) |
||||
f8g5_19 := int64(f8) * int64(g5_19) |
||||
f8g6_19 := int64(f8) * int64(g6_19) |
||||
f8g7_19 := int64(f8) * int64(g7_19) |
||||
f8g8_19 := int64(f8) * int64(g8_19) |
||||
f8g9_19 := int64(f8) * int64(g9_19) |
||||
f9g0 := int64(f9) * int64(g0) |
||||
f9g1_38 := int64(f9_2) * int64(g1_19) |
||||
f9g2_19 := int64(f9) * int64(g2_19) |
||||
f9g3_38 := int64(f9_2) * int64(g3_19) |
||||
f9g4_19 := int64(f9) * int64(g4_19) |
||||
f9g5_38 := int64(f9_2) * int64(g5_19) |
||||
f9g6_19 := int64(f9) * int64(g6_19) |
||||
f9g7_38 := int64(f9_2) * int64(g7_19) |
||||
f9g8_19 := int64(f9) * int64(g8_19) |
||||
f9g9_38 := int64(f9_2) * int64(g9_19) |
||||
h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38 |
||||
h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19 |
||||
h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38 |
||||
h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19 |
||||
h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38 |
||||
h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19 |
||||
h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38 |
||||
h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19 |
||||
h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38 |
||||
h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0 |
||||
var carry [10]int64 |
||||
|
||||
// |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
|
||||
// i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
|
||||
// |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
|
||||
// i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
carry[4] = (h4 + (1 << 25)) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
// |h0| <= 2^25
|
||||
// |h4| <= 2^25
|
||||
// |h1| <= 1.51*2^58
|
||||
// |h5| <= 1.51*2^58
|
||||
|
||||
carry[1] = (h1 + (1 << 24)) >> 25 |
||||
h2 += carry[1] |
||||
h1 -= carry[1] << 25 |
||||
carry[5] = (h5 + (1 << 24)) >> 25 |
||||
h6 += carry[5] |
||||
h5 -= carry[5] << 25 |
||||
// |h1| <= 2^24; from now on fits into int32
|
||||
// |h5| <= 2^24; from now on fits into int32
|
||||
// |h2| <= 1.21*2^59
|
||||
// |h6| <= 1.21*2^59
|
||||
|
||||
carry[2] = (h2 + (1 << 25)) >> 26 |
||||
h3 += carry[2] |
||||
h2 -= carry[2] << 26 |
||||
carry[6] = (h6 + (1 << 25)) >> 26 |
||||
h7 += carry[6] |
||||
h6 -= carry[6] << 26 |
||||
// |h2| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h6| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h3| <= 1.51*2^58
|
||||
// |h7| <= 1.51*2^58
|
||||
|
||||
carry[3] = (h3 + (1 << 24)) >> 25 |
||||
h4 += carry[3] |
||||
h3 -= carry[3] << 25 |
||||
carry[7] = (h7 + (1 << 24)) >> 25 |
||||
h8 += carry[7] |
||||
h7 -= carry[7] << 25 |
||||
// |h3| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h7| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h4| <= 1.52*2^33
|
||||
// |h8| <= 1.52*2^33
|
||||
const ( |
||||
// ScalarSize is the size of the scalar input to X25519.
|
||||
ScalarSize = 32 |
||||
// PointSize is the size of the point input to X25519.
|
||||
PointSize = 32 |
||||
) |
||||
|
||||
carry[4] = (h4 + (1 << 25)) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
carry[8] = (h8 + (1 << 25)) >> 26 |
||||
h9 += carry[8] |
||||
h8 -= carry[8] << 26 |
||||
// |h4| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h8| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h5| <= 1.01*2^24
|
||||
// |h9| <= 1.51*2^58
|
||||
// Basepoint is the canonical Curve25519 generator.
|
||||
var Basepoint []byte |
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25 |
||||
h0 += carry[9] * 19 |
||||
h9 -= carry[9] << 25 |
||||
// |h9| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h0| <= 1.8*2^37
|
||||
var basePoint = [32]byte{9, 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} |
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
// |h0| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h1| <= 1.01*2^24
|
||||
func init() { Basepoint = basePoint[:] } |
||||
|
||||
h[0] = int32(h0) |
||||
h[1] = int32(h1) |
||||
h[2] = int32(h2) |
||||
h[3] = int32(h3) |
||||
h[4] = int32(h4) |
||||
h[5] = int32(h5) |
||||
h[6] = int32(h6) |
||||
h[7] = int32(h7) |
||||
h[8] = int32(h8) |
||||
h[9] = int32(h9) |
||||
func checkBasepoint() { |
||||
if subtle.ConstantTimeCompare(Basepoint, []byte{ |
||||
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
}) != 1 { |
||||
panic("curve25519: global Basepoint value was modified") |
||||
} |
||||
|
||||
// feSquare calculates h = f*f. Can overlap h with f.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
func feSquare(h, f *fieldElement) { |
||||
f0 := f[0] |
||||
f1 := f[1] |
||||
f2 := f[2] |
||||
f3 := f[3] |
||||
f4 := f[4] |
||||
f5 := f[5] |
||||
f6 := f[6] |
||||
f7 := f[7] |
||||
f8 := f[8] |
||||
f9 := f[9] |
||||
f0_2 := 2 * f0 |
||||
f1_2 := 2 * f1 |
||||
f2_2 := 2 * f2 |
||||
f3_2 := 2 * f3 |
||||
f4_2 := 2 * f4 |
||||
f5_2 := 2 * f5 |
||||
f6_2 := 2 * f6 |
||||
f7_2 := 2 * f7 |
||||
f5_38 := 38 * f5 // 1.31*2^30
|
||||
f6_19 := 19 * f6 // 1.31*2^30
|
||||
f7_38 := 38 * f7 // 1.31*2^30
|
||||
f8_19 := 19 * f8 // 1.31*2^30
|
||||
f9_38 := 38 * f9 // 1.31*2^30
|
||||
f0f0 := int64(f0) * int64(f0) |
||||
f0f1_2 := int64(f0_2) * int64(f1) |
||||
f0f2_2 := int64(f0_2) * int64(f2) |
||||
f0f3_2 := int64(f0_2) * int64(f3) |
||||
f0f4_2 := int64(f0_2) * int64(f4) |
||||
f0f5_2 := int64(f0_2) * int64(f5) |
||||
f0f6_2 := int64(f0_2) * int64(f6) |
||||
f0f7_2 := int64(f0_2) * int64(f7) |
||||
f0f8_2 := int64(f0_2) * int64(f8) |
||||
f0f9_2 := int64(f0_2) * int64(f9) |
||||
f1f1_2 := int64(f1_2) * int64(f1) |
||||
f1f2_2 := int64(f1_2) * int64(f2) |
||||
f1f3_4 := int64(f1_2) * int64(f3_2) |
||||
f1f4_2 := int64(f1_2) * int64(f4) |
||||
f1f5_4 := int64(f1_2) * int64(f5_2) |
||||
f1f6_2 := int64(f1_2) * int64(f6) |
||||
f1f7_4 := int64(f1_2) * int64(f7_2) |
||||
f1f8_2 := int64(f1_2) * int64(f8) |
||||
f1f9_76 := int64(f1_2) * int64(f9_38) |
||||
f2f2 := int64(f2) * int64(f2) |
||||
f2f3_2 := int64(f2_2) * int64(f3) |
||||
f2f4_2 := int64(f2_2) * int64(f4) |
||||
f2f5_2 := int64(f2_2) * int64(f5) |
||||
f2f6_2 := int64(f2_2) * int64(f6) |
||||
f2f7_2 := int64(f2_2) * int64(f7) |
||||
f2f8_38 := int64(f2_2) * int64(f8_19) |
||||
f2f9_38 := int64(f2) * int64(f9_38) |
||||
f3f3_2 := int64(f3_2) * int64(f3) |
||||
f3f4_2 := int64(f3_2) * int64(f4) |
||||
f3f5_4 := int64(f3_2) * int64(f5_2) |
||||
f3f6_2 := int64(f3_2) * int64(f6) |
||||
f3f7_76 := int64(f3_2) * int64(f7_38) |
||||
f3f8_38 := int64(f3_2) * int64(f8_19) |
||||
f3f9_76 := int64(f3_2) * int64(f9_38) |
||||
f4f4 := int64(f4) * int64(f4) |
||||
f4f5_2 := int64(f4_2) * int64(f5) |
||||
f4f6_38 := int64(f4_2) * int64(f6_19) |
||||
f4f7_38 := int64(f4) * int64(f7_38) |
||||
f4f8_38 := int64(f4_2) * int64(f8_19) |
||||
f4f9_38 := int64(f4) * int64(f9_38) |
||||
f5f5_38 := int64(f5) * int64(f5_38) |
||||
f5f6_38 := int64(f5_2) * int64(f6_19) |
||||
f5f7_76 := int64(f5_2) * int64(f7_38) |
||||
f5f8_38 := int64(f5_2) * int64(f8_19) |
||||
f5f9_76 := int64(f5_2) * int64(f9_38) |
||||
f6f6_19 := int64(f6) * int64(f6_19) |
||||
f6f7_38 := int64(f6) * int64(f7_38) |
||||
f6f8_38 := int64(f6_2) * int64(f8_19) |
||||
f6f9_38 := int64(f6) * int64(f9_38) |
||||
f7f7_38 := int64(f7) * int64(f7_38) |
||||
f7f8_38 := int64(f7_2) * int64(f8_19) |
||||
f7f9_76 := int64(f7_2) * int64(f9_38) |
||||
f8f8_19 := int64(f8) * int64(f8_19) |
||||
f8f9_38 := int64(f8) * int64(f9_38) |
||||
f9f9_38 := int64(f9) * int64(f9_38) |
||||
h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38 |
||||
h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38 |
||||
h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19 |
||||
h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38 |
||||
h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38 |
||||
h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38 |
||||
h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19 |
||||
h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38 |
||||
h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38 |
||||
h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2 |
||||
var carry [10]int64 |
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
carry[4] = (h4 + (1 << 25)) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
|
||||
carry[1] = (h1 + (1 << 24)) >> 25 |
||||
h2 += carry[1] |
||||
h1 -= carry[1] << 25 |
||||
carry[5] = (h5 + (1 << 24)) >> 25 |
||||
h6 += carry[5] |
||||
h5 -= carry[5] << 25 |
||||
|
||||
carry[2] = (h2 + (1 << 25)) >> 26 |
||||
h3 += carry[2] |
||||
h2 -= carry[2] << 26 |
||||
carry[6] = (h6 + (1 << 25)) >> 26 |
||||
h7 += carry[6] |
||||
h6 -= carry[6] << 26 |
||||
|
||||
carry[3] = (h3 + (1 << 24)) >> 25 |
||||
h4 += carry[3] |
||||
h3 -= carry[3] << 25 |
||||
carry[7] = (h7 + (1 << 24)) >> 25 |
||||
h8 += carry[7] |
||||
h7 -= carry[7] << 25 |
||||
|
||||
carry[4] = (h4 + (1 << 25)) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
carry[8] = (h8 + (1 << 25)) >> 26 |
||||
h9 += carry[8] |
||||
h8 -= carry[8] << 26 |
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25 |
||||
h0 += carry[9] * 19 |
||||
h9 -= carry[9] << 25 |
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
|
||||
h[0] = int32(h0) |
||||
h[1] = int32(h1) |
||||
h[2] = int32(h2) |
||||
h[3] = int32(h3) |
||||
h[4] = int32(h4) |
||||
h[5] = int32(h5) |
||||
h[6] = int32(h6) |
||||
h[7] = int32(h7) |
||||
h[8] = int32(h8) |
||||
h[9] = int32(h9) |
||||
} |
||||
|
||||
// feMul121666 calculates h = f * 121666. Can overlap h with f.
|
||||
// X25519 returns the result of the scalar multiplication (scalar * point),
|
||||
// according to RFC 7748, Section 5. scalar, point and the return value are
|
||||
// slices of 32 bytes.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
// scalar can be generated at random, for example with crypto/rand. point should
|
||||
// be either Basepoint or the output of another X25519 call.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
func feMul121666(h, f *fieldElement) { |
||||
h0 := int64(f[0]) * 121666 |
||||
h1 := int64(f[1]) * 121666 |
||||
h2 := int64(f[2]) * 121666 |
||||
h3 := int64(f[3]) * 121666 |
||||
h4 := int64(f[4]) * 121666 |
||||
h5 := int64(f[5]) * 121666 |
||||
h6 := int64(f[6]) * 121666 |
||||
h7 := int64(f[7]) * 121666 |
||||
h8 := int64(f[8]) * 121666 |
||||
h9 := int64(f[9]) * 121666 |
||||
var carry [10]int64 |
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25 |
||||
h0 += carry[9] * 19 |
||||
h9 -= carry[9] << 25 |
||||
carry[1] = (h1 + (1 << 24)) >> 25 |
||||
h2 += carry[1] |
||||
h1 -= carry[1] << 25 |
||||
carry[3] = (h3 + (1 << 24)) >> 25 |
||||
h4 += carry[3] |
||||
h3 -= carry[3] << 25 |
||||
carry[5] = (h5 + (1 << 24)) >> 25 |
||||
h6 += carry[5] |
||||
h5 -= carry[5] << 25 |
||||
carry[7] = (h7 + (1 << 24)) >> 25 |
||||
h8 += carry[7] |
||||
h7 -= carry[7] << 25 |
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
carry[2] = (h2 + (1 << 25)) >> 26 |
||||
h3 += carry[2] |
||||
h2 -= carry[2] << 26 |
||||
carry[4] = (h4 + (1 << 25)) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
carry[6] = (h6 + (1 << 25)) >> 26 |
||||
h7 += carry[6] |
||||
h6 -= carry[6] << 26 |
||||
carry[8] = (h8 + (1 << 25)) >> 26 |
||||
h9 += carry[8] |
||||
h8 -= carry[8] << 26 |
||||
|
||||
h[0] = int32(h0) |
||||
h[1] = int32(h1) |
||||
h[2] = int32(h2) |
||||
h[3] = int32(h3) |
||||
h[4] = int32(h4) |
||||
h[5] = int32(h5) |
||||
h[6] = int32(h6) |
||||
h[7] = int32(h7) |
||||
h[8] = int32(h8) |
||||
h[9] = int32(h9) |
||||
// If point is Basepoint (but not if it's a different slice with the same
|
||||
// contents) a precomputed implementation might be used for performance.
|
||||
func X25519(scalar, point []byte) ([]byte, error) { |
||||
// Outline the body of function, to let the allocation be inlined in the
|
||||
// caller, and possibly avoid escaping to the heap.
|
||||
var dst [32]byte |
||||
return x25519(&dst, scalar, point) |
||||
} |
||||
|
||||
// feInvert sets out = z^-1.
|
||||
func feInvert(out, z *fieldElement) { |
||||
var t0, t1, t2, t3 fieldElement |
||||
var i int |
||||
|
||||
feSquare(&t0, z) |
||||
for i = 1; i < 1; i++ { |
||||
feSquare(&t0, &t0) |
||||
} |
||||
feSquare(&t1, &t0) |
||||
for i = 1; i < 2; i++ { |
||||
feSquare(&t1, &t1) |
||||
} |
||||
feMul(&t1, z, &t1) |
||||
feMul(&t0, &t0, &t1) |
||||
feSquare(&t2, &t0) |
||||
for i = 1; i < 1; i++ { |
||||
feSquare(&t2, &t2) |
||||
} |
||||
feMul(&t1, &t1, &t2) |
||||
feSquare(&t2, &t1) |
||||
for i = 1; i < 5; i++ { |
||||
feSquare(&t2, &t2) |
||||
} |
||||
feMul(&t1, &t2, &t1) |
||||
feSquare(&t2, &t1) |
||||
for i = 1; i < 10; i++ { |
||||
feSquare(&t2, &t2) |
||||
} |
||||
feMul(&t2, &t2, &t1) |
||||
feSquare(&t3, &t2) |
||||
for i = 1; i < 20; i++ { |
||||
feSquare(&t3, &t3) |
||||
} |
||||
feMul(&t2, &t3, &t2) |
||||
feSquare(&t2, &t2) |
||||
for i = 1; i < 10; i++ { |
||||
feSquare(&t2, &t2) |
||||
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) { |
||||
var in [32]byte |
||||
if l := len(scalar); l != 32 { |
||||
return nil, fmt.Errorf("bad scalar length: %d, expected %d", l, 32) |
||||
} |
||||
feMul(&t1, &t2, &t1) |
||||
feSquare(&t2, &t1) |
||||
for i = 1; i < 50; i++ { |
||||
feSquare(&t2, &t2) |
||||
if l := len(point); l != 32 { |
||||
return nil, fmt.Errorf("bad point length: %d, expected %d", l, 32) |
||||
} |
||||
feMul(&t2, &t2, &t1) |
||||
feSquare(&t3, &t2) |
||||
for i = 1; i < 100; i++ { |
||||
feSquare(&t3, &t3) |
||||
copy(in[:], scalar) |
||||
if &point[0] == &Basepoint[0] { |
||||
checkBasepoint() |
||||
ScalarBaseMult(dst, &in) |
||||
} else { |
||||
var base, zero [32]byte |
||||
copy(base[:], point) |
||||
ScalarMult(dst, &in, &base) |
||||
if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 { |
||||
return nil, fmt.Errorf("bad input point: low order point") |
||||
} |
||||
feMul(&t2, &t3, &t2) |
||||
feSquare(&t2, &t2) |
||||
for i = 1; i < 50; i++ { |
||||
feSquare(&t2, &t2) |
||||
} |
||||
feMul(&t1, &t2, &t1) |
||||
feSquare(&t1, &t1) |
||||
for i = 1; i < 5; i++ { |
||||
feSquare(&t1, &t1) |
||||
} |
||||
feMul(out, &t1, &t0) |
||||
} |
||||
|
||||
func scalarMult(out, in, base *[32]byte) { |
||||
var e [32]byte |
||||
|
||||
copy(e[:], in[:]) |
||||
e[0] &= 248 |
||||
e[31] &= 127 |
||||
e[31] |= 64 |
||||
|
||||
var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement |
||||
feFromBytes(&x1, base) |
||||
feOne(&x2) |
||||
feCopy(&x3, &x1) |
||||
feOne(&z3) |
||||
|
||||
swap := int32(0) |
||||
for pos := 254; pos >= 0; pos-- { |
||||
b := e[pos/8] >> uint(pos&7) |
||||
b &= 1 |
||||
swap ^= int32(b) |
||||
feCSwap(&x2, &x3, swap) |
||||
feCSwap(&z2, &z3, swap) |
||||
swap = int32(b) |
||||
|
||||
feSub(&tmp0, &x3, &z3) |
||||
feSub(&tmp1, &x2, &z2) |
||||
feAdd(&x2, &x2, &z2) |
||||
feAdd(&z2, &x3, &z3) |
||||
feMul(&z3, &tmp0, &x2) |
||||
feMul(&z2, &z2, &tmp1) |
||||
feSquare(&tmp0, &tmp1) |
||||
feSquare(&tmp1, &x2) |
||||
feAdd(&x3, &z3, &z2) |
||||
feSub(&z2, &z3, &z2) |
||||
feMul(&x2, &tmp1, &tmp0) |
||||
feSub(&tmp1, &tmp1, &tmp0) |
||||
feSquare(&z2, &z2) |
||||
feMul121666(&z3, &tmp1) |
||||
feSquare(&x3, &x3) |
||||
feAdd(&tmp0, &tmp0, &z3) |
||||
feMul(&z3, &x1, &z2) |
||||
feMul(&z2, &tmp1, &tmp0) |
||||
} |
||||
|
||||
feCSwap(&x2, &x3, swap) |
||||
feCSwap(&z2, &z3, swap) |
||||
|
||||
feInvert(&z2, &z2) |
||||
feMul(&x2, &x2, &z2) |
||||
feToBytes(out, &x2) |
||||
return dst[:], nil |
||||
} |
||||
|
@ -0,0 +1,828 @@ |
||||
// Copyright 2013 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 curve25519 |
||||
|
||||
import "encoding/binary" |
||||
|
||||
// This code is a port of the public domain, "ref10" implementation of
|
||||
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
|
||||
|
||||
// fieldElement represents an element of the field GF(2^255 - 19). An element
|
||||
// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
|
||||
// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
|
||||
// context.
|
||||
type fieldElement [10]int32 |
||||
|
||||
func feZero(fe *fieldElement) { |
||||
for i := range fe { |
||||
fe[i] = 0 |
||||
} |
||||
} |
||||
|
||||
func feOne(fe *fieldElement) { |
||||
feZero(fe) |
||||
fe[0] = 1 |
||||
} |
||||
|
||||
func feAdd(dst, a, b *fieldElement) { |
||||
for i := range dst { |
||||
dst[i] = a[i] + b[i] |
||||
} |
||||
} |
||||
|
||||
func feSub(dst, a, b *fieldElement) { |
||||
for i := range dst { |
||||
dst[i] = a[i] - b[i] |
||||
} |
||||
} |
||||
|
||||
func feCopy(dst, src *fieldElement) { |
||||
for i := range dst { |
||||
dst[i] = src[i] |
||||
} |
||||
} |
||||
|
||||
// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
|
||||
//
|
||||
// Preconditions: b in {0,1}.
|
||||
func feCSwap(f, g *fieldElement, b int32) { |
||||
b = -b |
||||
for i := range f { |
||||
t := b & (f[i] ^ g[i]) |
||||
f[i] ^= t |
||||
g[i] ^= t |
||||
} |
||||
} |
||||
|
||||
// load3 reads a 24-bit, little-endian value from in.
|
||||
func load3(in []byte) int64 { |
||||
var r int64 |
||||
r = int64(in[0]) |
||||
r |= int64(in[1]) << 8 |
||||
r |= int64(in[2]) << 16 |
||||
return r |
||||
} |
||||
|
||||
// load4 reads a 32-bit, little-endian value from in.
|
||||
func load4(in []byte) int64 { |
||||
return int64(binary.LittleEndian.Uint32(in)) |
||||
} |
||||
|
||||
func feFromBytes(dst *fieldElement, src *[32]byte) { |
||||
h0 := load4(src[:]) |
||||
h1 := load3(src[4:]) << 6 |
||||
h2 := load3(src[7:]) << 5 |
||||
h3 := load3(src[10:]) << 3 |
||||
h4 := load3(src[13:]) << 2 |
||||
h5 := load4(src[16:]) |
||||
h6 := load3(src[20:]) << 7 |
||||
h7 := load3(src[23:]) << 5 |
||||
h8 := load3(src[26:]) << 4 |
||||
h9 := (load3(src[29:]) & 0x7fffff) << 2 |
||||
|
||||
var carry [10]int64 |
||||
carry[9] = (h9 + 1<<24) >> 25 |
||||
h0 += carry[9] * 19 |
||||
h9 -= carry[9] << 25 |
||||
carry[1] = (h1 + 1<<24) >> 25 |
||||
h2 += carry[1] |
||||
h1 -= carry[1] << 25 |
||||
carry[3] = (h3 + 1<<24) >> 25 |
||||
h4 += carry[3] |
||||
h3 -= carry[3] << 25 |
||||
carry[5] = (h5 + 1<<24) >> 25 |
||||
h6 += carry[5] |
||||
h5 -= carry[5] << 25 |
||||
carry[7] = (h7 + 1<<24) >> 25 |
||||
h8 += carry[7] |
||||
h7 -= carry[7] << 25 |
||||
|
||||
carry[0] = (h0 + 1<<25) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
carry[2] = (h2 + 1<<25) >> 26 |
||||
h3 += carry[2] |
||||
h2 -= carry[2] << 26 |
||||
carry[4] = (h4 + 1<<25) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
carry[6] = (h6 + 1<<25) >> 26 |
||||
h7 += carry[6] |
||||
h6 -= carry[6] << 26 |
||||
carry[8] = (h8 + 1<<25) >> 26 |
||||
h9 += carry[8] |
||||
h8 -= carry[8] << 26 |
||||
|
||||
dst[0] = int32(h0) |
||||
dst[1] = int32(h1) |
||||
dst[2] = int32(h2) |
||||
dst[3] = int32(h3) |
||||
dst[4] = int32(h4) |
||||
dst[5] = int32(h5) |
||||
dst[6] = int32(h6) |
||||
dst[7] = int32(h7) |
||||
dst[8] = int32(h8) |
||||
dst[9] = int32(h9) |
||||
} |
||||
|
||||
// feToBytes marshals h to s.
|
||||
// Preconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
//
|
||||
// Write p=2^255-19; q=floor(h/p).
|
||||
// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
|
||||
//
|
||||
// Proof:
|
||||
// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
|
||||
// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
|
||||
//
|
||||
// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
|
||||
// Then 0<y<1.
|
||||
//
|
||||
// Write r=h-pq.
|
||||
// Have 0<=r<=p-1=2^255-20.
|
||||
// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
|
||||
//
|
||||
// Write x=r+19(2^-255)r+y.
|
||||
// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
|
||||
//
|
||||
// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
|
||||
// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
|
||||
func feToBytes(s *[32]byte, h *fieldElement) { |
||||
var carry [10]int32 |
||||
|
||||
q := (19*h[9] + (1 << 24)) >> 25 |
||||
q = (h[0] + q) >> 26 |
||||
q = (h[1] + q) >> 25 |
||||
q = (h[2] + q) >> 26 |
||||
q = (h[3] + q) >> 25 |
||||
q = (h[4] + q) >> 26 |
||||
q = (h[5] + q) >> 25 |
||||
q = (h[6] + q) >> 26 |
||||
q = (h[7] + q) >> 25 |
||||
q = (h[8] + q) >> 26 |
||||
q = (h[9] + q) >> 25 |
||||
|
||||
// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
|
||||
h[0] += 19 * q |
||||
// Goal: Output h-2^255 q, which is between 0 and 2^255-20.
|
||||
|
||||
carry[0] = h[0] >> 26 |
||||
h[1] += carry[0] |
||||
h[0] -= carry[0] << 26 |
||||
carry[1] = h[1] >> 25 |
||||
h[2] += carry[1] |
||||
h[1] -= carry[1] << 25 |
||||
carry[2] = h[2] >> 26 |
||||
h[3] += carry[2] |
||||
h[2] -= carry[2] << 26 |
||||
carry[3] = h[3] >> 25 |
||||
h[4] += carry[3] |
||||
h[3] -= carry[3] << 25 |
||||
carry[4] = h[4] >> 26 |
||||
h[5] += carry[4] |
||||
h[4] -= carry[4] << 26 |
||||
carry[5] = h[5] >> 25 |
||||
h[6] += carry[5] |
||||
h[5] -= carry[5] << 25 |
||||
carry[6] = h[6] >> 26 |
||||
h[7] += carry[6] |
||||
h[6] -= carry[6] << 26 |
||||
carry[7] = h[7] >> 25 |
||||
h[8] += carry[7] |
||||
h[7] -= carry[7] << 25 |
||||
carry[8] = h[8] >> 26 |
||||
h[9] += carry[8] |
||||
h[8] -= carry[8] << 26 |
||||
carry[9] = h[9] >> 25 |
||||
h[9] -= carry[9] << 25 |
||||
// h10 = carry9
|
||||
|
||||
// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
|
||||
// Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
|
||||
// evidently 2^255 h10-2^255 q = 0.
|
||||
// Goal: Output h[0]+...+2^230 h[9].
|
||||
|
||||
s[0] = byte(h[0] >> 0) |
||||
s[1] = byte(h[0] >> 8) |
||||
s[2] = byte(h[0] >> 16) |
||||
s[3] = byte((h[0] >> 24) | (h[1] << 2)) |
||||
s[4] = byte(h[1] >> 6) |
||||
s[5] = byte(h[1] >> 14) |
||||
s[6] = byte((h[1] >> 22) | (h[2] << 3)) |
||||
s[7] = byte(h[2] >> 5) |
||||
s[8] = byte(h[2] >> 13) |
||||
s[9] = byte((h[2] >> 21) | (h[3] << 5)) |
||||
s[10] = byte(h[3] >> 3) |
||||
s[11] = byte(h[3] >> 11) |
||||
s[12] = byte((h[3] >> 19) | (h[4] << 6)) |
||||
s[13] = byte(h[4] >> 2) |
||||
s[14] = byte(h[4] >> 10) |
||||
s[15] = byte(h[4] >> 18) |
||||
s[16] = byte(h[5] >> 0) |
||||
s[17] = byte(h[5] >> 8) |
||||
s[18] = byte(h[5] >> 16) |
||||
s[19] = byte((h[5] >> 24) | (h[6] << 1)) |
||||
s[20] = byte(h[6] >> 7) |
||||
s[21] = byte(h[6] >> 15) |
||||
s[22] = byte((h[6] >> 23) | (h[7] << 3)) |
||||
s[23] = byte(h[7] >> 5) |
||||
s[24] = byte(h[7] >> 13) |
||||
s[25] = byte((h[7] >> 21) | (h[8] << 4)) |
||||
s[26] = byte(h[8] >> 4) |
||||
s[27] = byte(h[8] >> 12) |
||||
s[28] = byte((h[8] >> 20) | (h[9] << 6)) |
||||
s[29] = byte(h[9] >> 2) |
||||
s[30] = byte(h[9] >> 10) |
||||
s[31] = byte(h[9] >> 18) |
||||
} |
||||
|
||||
// feMul calculates h = f * g
|
||||
// Can overlap h with f or g.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
//
|
||||
// Notes on implementation strategy:
|
||||
//
|
||||
// Using schoolbook multiplication.
|
||||
// Karatsuba would save a little in some cost models.
|
||||
//
|
||||
// Most multiplications by 2 and 19 are 32-bit precomputations;
|
||||
// cheaper than 64-bit postcomputations.
|
||||
//
|
||||
// There is one remaining multiplication by 19 in the carry chain;
|
||||
// one *19 precomputation can be merged into this,
|
||||
// but the resulting data flow is considerably less clean.
|
||||
//
|
||||
// There are 12 carries below.
|
||||
// 10 of them are 2-way parallelizable and vectorizable.
|
||||
// Can get away with 11 carries, but then data flow is much deeper.
|
||||
//
|
||||
// With tighter constraints on inputs can squeeze carries into int32.
|
||||
func feMul(h, f, g *fieldElement) { |
||||
f0 := f[0] |
||||
f1 := f[1] |
||||
f2 := f[2] |
||||
f3 := f[3] |
||||
f4 := f[4] |
||||
f5 := f[5] |
||||
f6 := f[6] |
||||
f7 := f[7] |
||||
f8 := f[8] |
||||
f9 := f[9] |
||||
g0 := g[0] |
||||
g1 := g[1] |
||||
g2 := g[2] |
||||
g3 := g[3] |
||||
g4 := g[4] |
||||
g5 := g[5] |
||||
g6 := g[6] |
||||
g7 := g[7] |
||||
g8 := g[8] |
||||
g9 := g[9] |
||||
g1_19 := 19 * g1 // 1.4*2^29
|
||||
g2_19 := 19 * g2 // 1.4*2^30; still ok
|
||||
g3_19 := 19 * g3 |
||||
g4_19 := 19 * g4 |
||||
g5_19 := 19 * g5 |
||||
g6_19 := 19 * g6 |
||||
g7_19 := 19 * g7 |
||||
g8_19 := 19 * g8 |
||||
g9_19 := 19 * g9 |
||||
f1_2 := 2 * f1 |
||||
f3_2 := 2 * f3 |
||||
f5_2 := 2 * f5 |
||||
f7_2 := 2 * f7 |
||||
f9_2 := 2 * f9 |
||||
f0g0 := int64(f0) * int64(g0) |
||||
f0g1 := int64(f0) * int64(g1) |
||||
f0g2 := int64(f0) * int64(g2) |
||||
f0g3 := int64(f0) * int64(g3) |
||||
f0g4 := int64(f0) * int64(g4) |
||||
f0g5 := int64(f0) * int64(g5) |
||||
f0g6 := int64(f0) * int64(g6) |
||||
f0g7 := int64(f0) * int64(g7) |
||||
f0g8 := int64(f0) * int64(g8) |
||||
f0g9 := int64(f0) * int64(g9) |
||||
f1g0 := int64(f1) * int64(g0) |
||||
f1g1_2 := int64(f1_2) * int64(g1) |
||||
f1g2 := int64(f1) * int64(g2) |
||||
f1g3_2 := int64(f1_2) * int64(g3) |
||||
f1g4 := int64(f1) * int64(g4) |
||||
f1g5_2 := int64(f1_2) * int64(g5) |
||||
f1g6 := int64(f1) * int64(g6) |
||||
f1g7_2 := int64(f1_2) * int64(g7) |
||||
f1g8 := int64(f1) * int64(g8) |
||||
f1g9_38 := int64(f1_2) * int64(g9_19) |
||||
f2g0 := int64(f2) * int64(g0) |
||||
f2g1 := int64(f2) * int64(g1) |
||||
f2g2 := int64(f2) * int64(g2) |
||||
f2g3 := int64(f2) * int64(g3) |
||||
f2g4 := int64(f2) * int64(g4) |
||||
f2g5 := int64(f2) * int64(g5) |
||||
f2g6 := int64(f2) * int64(g6) |
||||
f2g7 := int64(f2) * int64(g7) |
||||
f2g8_19 := int64(f2) * int64(g8_19) |
||||
f2g9_19 := int64(f2) * int64(g9_19) |
||||
f3g0 := int64(f3) * int64(g0) |
||||
f3g1_2 := int64(f3_2) * int64(g1) |
||||
f3g2 := int64(f3) * int64(g2) |
||||
f3g3_2 := int64(f3_2) * int64(g3) |
||||
f3g4 := int64(f3) * int64(g4) |
||||
f3g5_2 := int64(f3_2) * int64(g5) |
||||
f3g6 := int64(f3) * int64(g6) |
||||
f3g7_38 := int64(f3_2) * int64(g7_19) |
||||
f3g8_19 := int64(f3) * int64(g8_19) |
||||
f3g9_38 := int64(f3_2) * int64(g9_19) |
||||
f4g0 := int64(f4) * int64(g0) |
||||
f4g1 := int64(f4) * int64(g1) |
||||
f4g2 := int64(f4) * int64(g2) |
||||
f4g3 := int64(f4) * int64(g3) |
||||
f4g4 := int64(f4) * int64(g4) |
||||
f4g5 := int64(f4) * int64(g5) |
||||
f4g6_19 := int64(f4) * int64(g6_19) |
||||
f4g7_19 := int64(f4) * int64(g7_19) |
||||
f4g8_19 := int64(f4) * int64(g8_19) |
||||
f4g9_19 := int64(f4) * int64(g9_19) |
||||
f5g0 := int64(f5) * int64(g0) |
||||
f5g1_2 := int64(f5_2) * int64(g1) |
||||
f5g2 := int64(f5) * int64(g2) |
||||
f5g3_2 := int64(f5_2) * int64(g3) |
||||
f5g4 := int64(f5) * int64(g4) |
||||
f5g5_38 := int64(f5_2) * int64(g5_19) |
||||
f5g6_19 := int64(f5) * int64(g6_19) |
||||
f5g7_38 := int64(f5_2) * int64(g7_19) |
||||
f5g8_19 := int64(f5) * int64(g8_19) |
||||
f5g9_38 := int64(f5_2) * int64(g9_19) |
||||
f6g0 := int64(f6) * int64(g0) |
||||
f6g1 := int64(f6) * int64(g1) |
||||
f6g2 := int64(f6) * int64(g2) |
||||
f6g3 := int64(f6) * int64(g3) |
||||
f6g4_19 := int64(f6) * int64(g4_19) |
||||
f6g5_19 := int64(f6) * int64(g5_19) |
||||
f6g6_19 := int64(f6) * int64(g6_19) |
||||
f6g7_19 := int64(f6) * int64(g7_19) |
||||
f6g8_19 := int64(f6) * int64(g8_19) |
||||
f6g9_19 := int64(f6) * int64(g9_19) |
||||
f7g0 := int64(f7) * int64(g0) |
||||
f7g1_2 := int64(f7_2) * int64(g1) |
||||
f7g2 := int64(f7) * int64(g2) |
||||
f7g3_38 := int64(f7_2) * int64(g3_19) |
||||
f7g4_19 := int64(f7) * int64(g4_19) |
||||
f7g5_38 := int64(f7_2) * int64(g5_19) |
||||
f7g6_19 := int64(f7) * int64(g6_19) |
||||
f7g7_38 := int64(f7_2) * int64(g7_19) |
||||
f7g8_19 := int64(f7) * int64(g8_19) |
||||
f7g9_38 := int64(f7_2) * int64(g9_19) |
||||
f8g0 := int64(f8) * int64(g0) |
||||
f8g1 := int64(f8) * int64(g1) |
||||
f8g2_19 := int64(f8) * int64(g2_19) |
||||
f8g3_19 := int64(f8) * int64(g3_19) |
||||
f8g4_19 := int64(f8) * int64(g4_19) |
||||
f8g5_19 := int64(f8) * int64(g5_19) |
||||
f8g6_19 := int64(f8) * int64(g6_19) |
||||
f8g7_19 := int64(f8) * int64(g7_19) |
||||
f8g8_19 := int64(f8) * int64(g8_19) |
||||
f8g9_19 := int64(f8) * int64(g9_19) |
||||
f9g0 := int64(f9) * int64(g0) |
||||
f9g1_38 := int64(f9_2) * int64(g1_19) |
||||
f9g2_19 := int64(f9) * int64(g2_19) |
||||
f9g3_38 := int64(f9_2) * int64(g3_19) |
||||
f9g4_19 := int64(f9) * int64(g4_19) |
||||
f9g5_38 := int64(f9_2) * int64(g5_19) |
||||
f9g6_19 := int64(f9) * int64(g6_19) |
||||
f9g7_38 := int64(f9_2) * int64(g7_19) |
||||
f9g8_19 := int64(f9) * int64(g8_19) |
||||
f9g9_38 := int64(f9_2) * int64(g9_19) |
||||
h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38 |
||||
h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19 |
||||
h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38 |
||||
h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19 |
||||
h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38 |
||||
h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19 |
||||
h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38 |
||||
h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19 |
||||
h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38 |
||||
h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0 |
||||
var carry [10]int64 |
||||
|
||||
// |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
|
||||
// i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
|
||||
// |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
|
||||
// i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
carry[4] = (h4 + (1 << 25)) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
// |h0| <= 2^25
|
||||
// |h4| <= 2^25
|
||||
// |h1| <= 1.51*2^58
|
||||
// |h5| <= 1.51*2^58
|
||||
|
||||
carry[1] = (h1 + (1 << 24)) >> 25 |
||||
h2 += carry[1] |
||||
h1 -= carry[1] << 25 |
||||
carry[5] = (h5 + (1 << 24)) >> 25 |
||||
h6 += carry[5] |
||||
h5 -= carry[5] << 25 |
||||
// |h1| <= 2^24; from now on fits into int32
|
||||
// |h5| <= 2^24; from now on fits into int32
|
||||
// |h2| <= 1.21*2^59
|
||||
// |h6| <= 1.21*2^59
|
||||
|
||||
carry[2] = (h2 + (1 << 25)) >> 26 |
||||
h3 += carry[2] |
||||
h2 -= carry[2] << 26 |
||||
carry[6] = (h6 + (1 << 25)) >> 26 |
||||
h7 += carry[6] |
||||
h6 -= carry[6] << 26 |
||||
// |h2| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h6| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h3| <= 1.51*2^58
|
||||
// |h7| <= 1.51*2^58
|
||||
|
||||
carry[3] = (h3 + (1 << 24)) >> 25 |
||||
h4 += carry[3] |
||||
h3 -= carry[3] << 25 |
||||
carry[7] = (h7 + (1 << 24)) >> 25 |
||||
h8 += carry[7] |
||||
h7 -= carry[7] << 25 |
||||
// |h3| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h7| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h4| <= 1.52*2^33
|
||||
// |h8| <= 1.52*2^33
|
||||
|
||||
carry[4] = (h4 + (1 << 25)) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
carry[8] = (h8 + (1 << 25)) >> 26 |
||||
h9 += carry[8] |
||||
h8 -= carry[8] << 26 |
||||
// |h4| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h8| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h5| <= 1.01*2^24
|
||||
// |h9| <= 1.51*2^58
|
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25 |
||||
h0 += carry[9] * 19 |
||||
h9 -= carry[9] << 25 |
||||
// |h9| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h0| <= 1.8*2^37
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
// |h0| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h1| <= 1.01*2^24
|
||||
|
||||
h[0] = int32(h0) |
||||
h[1] = int32(h1) |
||||
h[2] = int32(h2) |
||||
h[3] = int32(h3) |
||||
h[4] = int32(h4) |
||||
h[5] = int32(h5) |
||||
h[6] = int32(h6) |
||||
h[7] = int32(h7) |
||||
h[8] = int32(h8) |
||||
h[9] = int32(h9) |
||||
} |
||||
|
||||
// feSquare calculates h = f*f. Can overlap h with f.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
func feSquare(h, f *fieldElement) { |
||||
f0 := f[0] |
||||
f1 := f[1] |
||||
f2 := f[2] |
||||
f3 := f[3] |
||||
f4 := f[4] |
||||
f5 := f[5] |
||||
f6 := f[6] |
||||
f7 := f[7] |
||||
f8 := f[8] |
||||
f9 := f[9] |
||||
f0_2 := 2 * f0 |
||||
f1_2 := 2 * f1 |
||||
f2_2 := 2 * f2 |
||||
f3_2 := 2 * f3 |
||||
f4_2 := 2 * f4 |
||||
f5_2 := 2 * f5 |
||||
f6_2 := 2 * f6 |
||||
f7_2 := 2 * f7 |
||||
f5_38 := 38 * f5 // 1.31*2^30
|
||||
f6_19 := 19 * f6 // 1.31*2^30
|
||||
f7_38 := 38 * f7 // 1.31*2^30
|
||||
f8_19 := 19 * f8 // 1.31*2^30
|
||||
f9_38 := 38 * f9 // 1.31*2^30
|
||||
f0f0 := int64(f0) * int64(f0) |
||||
f0f1_2 := int64(f0_2) * int64(f1) |
||||
f0f2_2 := int64(f0_2) * int64(f2) |
||||
f0f3_2 := int64(f0_2) * int64(f3) |
||||
f0f4_2 := int64(f0_2) * int64(f4) |
||||
f0f5_2 := int64(f0_2) * int64(f5) |
||||
f0f6_2 := int64(f0_2) * int64(f6) |
||||
f0f7_2 := int64(f0_2) * int64(f7) |
||||
f0f8_2 := int64(f0_2) * int64(f8) |
||||
f0f9_2 := int64(f0_2) * int64(f9) |
||||
f1f1_2 := int64(f1_2) * int64(f1) |
||||
f1f2_2 := int64(f1_2) * int64(f2) |
||||
f1f3_4 := int64(f1_2) * int64(f3_2) |
||||
f1f4_2 := int64(f1_2) * int64(f4) |
||||
f1f5_4 := int64(f1_2) * int64(f5_2) |
||||
f1f6_2 := int64(f1_2) * int64(f6) |
||||
f1f7_4 := int64(f1_2) * int64(f7_2) |
||||
f1f8_2 := int64(f1_2) * int64(f8) |
||||
f1f9_76 := int64(f1_2) * int64(f9_38) |
||||
f2f2 := int64(f2) * int64(f2) |
||||
f2f3_2 := int64(f2_2) * int64(f3) |
||||
f2f4_2 := int64(f2_2) * int64(f4) |
||||
f2f5_2 := int64(f2_2) * int64(f5) |
||||
f2f6_2 := int64(f2_2) * int64(f6) |
||||
f2f7_2 := int64(f2_2) * int64(f7) |
||||
f2f8_38 := int64(f2_2) * int64(f8_19) |
||||
f2f9_38 := int64(f2) * int64(f9_38) |
||||
f3f3_2 := int64(f3_2) * int64(f3) |
||||
f3f4_2 := int64(f3_2) * int64(f4) |
||||
f3f5_4 := int64(f3_2) * int64(f5_2) |
||||
f3f6_2 := int64(f3_2) * int64(f6) |
||||
f3f7_76 := int64(f3_2) * int64(f7_38) |
||||
f3f8_38 := int64(f3_2) * int64(f8_19) |
||||
f3f9_76 := int64(f3_2) * int64(f9_38) |
||||
f4f4 := int64(f4) * int64(f4) |
||||
f4f5_2 := int64(f4_2) * int64(f5) |
||||
f4f6_38 := int64(f4_2) * int64(f6_19) |
||||
f4f7_38 := int64(f4) * int64(f7_38) |
||||
f4f8_38 := int64(f4_2) * int64(f8_19) |
||||
f4f9_38 := int64(f4) * int64(f9_38) |
||||
f5f5_38 := int64(f5) * int64(f5_38) |
||||
f5f6_38 := int64(f5_2) * int64(f6_19) |
||||
f5f7_76 := int64(f5_2) * int64(f7_38) |
||||
f5f8_38 := int64(f5_2) * int64(f8_19) |
||||
f5f9_76 := int64(f5_2) * int64(f9_38) |
||||
f6f6_19 := int64(f6) * int64(f6_19) |
||||
f6f7_38 := int64(f6) * int64(f7_38) |
||||
f6f8_38 := int64(f6_2) * int64(f8_19) |
||||
f6f9_38 := int64(f6) * int64(f9_38) |
||||
f7f7_38 := int64(f7) * int64(f7_38) |
||||
f7f8_38 := int64(f7_2) * int64(f8_19) |
||||
f7f9_76 := int64(f7_2) * int64(f9_38) |
||||
f8f8_19 := int64(f8) * int64(f8_19) |
||||
f8f9_38 := int64(f8) * int64(f9_38) |
||||
f9f9_38 := int64(f9) * int64(f9_38) |
||||
h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38 |
||||
h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38 |
||||
h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19 |
||||
h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38 |
||||
h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38 |
||||
h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38 |
||||
h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19 |
||||
h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38 |
||||
h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38 |
||||
h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2 |
||||
var carry [10]int64 |
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
carry[4] = (h4 + (1 << 25)) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
|
||||
carry[1] = (h1 + (1 << 24)) >> 25 |
||||
h2 += carry[1] |
||||
h1 -= carry[1] << 25 |
||||
carry[5] = (h5 + (1 << 24)) >> 25 |
||||
h6 += carry[5] |
||||
h5 -= carry[5] << 25 |
||||
|
||||
carry[2] = (h2 + (1 << 25)) >> 26 |
||||
h3 += carry[2] |
||||
h2 -= carry[2] << 26 |
||||
carry[6] = (h6 + (1 << 25)) >> 26 |
||||
h7 += carry[6] |
||||
h6 -= carry[6] << 26 |
||||
|
||||
carry[3] = (h3 + (1 << 24)) >> 25 |
||||
h4 += carry[3] |
||||
h3 -= carry[3] << 25 |
||||
carry[7] = (h7 + (1 << 24)) >> 25 |
||||
h8 += carry[7] |
||||
h7 -= carry[7] << 25 |
||||
|
||||
carry[4] = (h4 + (1 << 25)) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
carry[8] = (h8 + (1 << 25)) >> 26 |
||||
h9 += carry[8] |
||||
h8 -= carry[8] << 26 |
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25 |
||||
h0 += carry[9] * 19 |
||||
h9 -= carry[9] << 25 |
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
|
||||
h[0] = int32(h0) |
||||
h[1] = int32(h1) |
||||
h[2] = int32(h2) |
||||
h[3] = int32(h3) |
||||
h[4] = int32(h4) |
||||
h[5] = int32(h5) |
||||
h[6] = int32(h6) |
||||
h[7] = int32(h7) |
||||
h[8] = int32(h8) |
||||
h[9] = int32(h9) |
||||
} |
||||
|
||||
// feMul121666 calculates h = f * 121666. Can overlap h with f.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
func feMul121666(h, f *fieldElement) { |
||||
h0 := int64(f[0]) * 121666 |
||||
h1 := int64(f[1]) * 121666 |
||||
h2 := int64(f[2]) * 121666 |
||||
h3 := int64(f[3]) * 121666 |
||||
h4 := int64(f[4]) * 121666 |
||||
h5 := int64(f[5]) * 121666 |
||||
h6 := int64(f[6]) * 121666 |
||||
h7 := int64(f[7]) * 121666 |
||||
h8 := int64(f[8]) * 121666 |
||||
h9 := int64(f[9]) * 121666 |
||||
var carry [10]int64 |
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25 |
||||
h0 += carry[9] * 19 |
||||
h9 -= carry[9] << 25 |
||||
carry[1] = (h1 + (1 << 24)) >> 25 |
||||
h2 += carry[1] |
||||
h1 -= carry[1] << 25 |
||||
carry[3] = (h3 + (1 << 24)) >> 25 |
||||
h4 += carry[3] |
||||
h3 -= carry[3] << 25 |
||||
carry[5] = (h5 + (1 << 24)) >> 25 |
||||
h6 += carry[5] |
||||
h5 -= carry[5] << 25 |
||||
carry[7] = (h7 + (1 << 24)) >> 25 |
||||
h8 += carry[7] |
||||
h7 -= carry[7] << 25 |
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26 |
||||
h1 += carry[0] |
||||
h0 -= carry[0] << 26 |
||||
carry[2] = (h2 + (1 << 25)) >> 26 |
||||
h3 += carry[2] |
||||
h2 -= carry[2] << 26 |
||||
carry[4] = (h4 + (1 << 25)) >> 26 |
||||
h5 += carry[4] |
||||
h4 -= carry[4] << 26 |
||||
carry[6] = (h6 + (1 << 25)) >> 26 |
||||
h7 += carry[6] |
||||
h6 -= carry[6] << 26 |
||||
carry[8] = (h8 + (1 << 25)) >> 26 |
||||
h9 += carry[8] |
||||
h8 -= carry[8] << 26 |
||||
|
||||
h[0] = int32(h0) |
||||
h[1] = int32(h1) |
||||
h[2] = int32(h2) |
||||
h[3] = int32(h3) |
||||
h[4] = int32(h4) |
||||
h[5] = int32(h5) |
||||
h[6] = int32(h6) |
||||
h[7] = int32(h7) |
||||
h[8] = int32(h8) |
||||
h[9] = int32(h9) |
||||
} |
||||
|
||||
// feInvert sets out = z^-1.
|
||||
func feInvert(out, z *fieldElement) { |
||||
var t0, t1, t2, t3 fieldElement |
||||
var i int |
||||
|
||||
feSquare(&t0, z) |
||||
for i = 1; i < 1; i++ { |
||||
feSquare(&t0, &t0) |
||||
} |
||||
feSquare(&t1, &t0) |
||||
for i = 1; i < 2; i++ { |
||||
feSquare(&t1, &t1) |
||||
} |
||||
feMul(&t1, z, &t1) |
||||
feMul(&t0, &t0, &t1) |
||||
feSquare(&t2, &t0) |
||||
for i = 1; i < 1; i++ { |
||||
feSquare(&t2, &t2) |
||||
} |
||||
feMul(&t1, &t1, &t2) |
||||
feSquare(&t2, &t1) |
||||
for i = 1; i < 5; i++ { |
||||
feSquare(&t2, &t2) |
||||
} |
||||
feMul(&t1, &t2, &t1) |
||||
feSquare(&t2, &t1) |
||||
for i = 1; i < 10; i++ { |
||||
feSquare(&t2, &t2) |
||||
} |
||||
feMul(&t2, &t2, &t1) |
||||
feSquare(&t3, &t2) |
||||
for i = 1; i < 20; i++ { |
||||
feSquare(&t3, &t3) |
||||
} |
||||
feMul(&t2, &t3, &t2) |
||||
feSquare(&t2, &t2) |
||||
for i = 1; i < 10; i++ { |
||||
feSquare(&t2, &t2) |
||||
} |
||||
feMul(&t1, &t2, &t1) |
||||
feSquare(&t2, &t1) |
||||
for i = 1; i < 50; i++ { |
||||
feSquare(&t2, &t2) |
||||
} |
||||
feMul(&t2, &t2, &t1) |
||||
feSquare(&t3, &t2) |
||||
for i = 1; i < 100; i++ { |
||||
feSquare(&t3, &t3) |
||||
} |
||||
feMul(&t2, &t3, &t2) |
||||
feSquare(&t2, &t2) |
||||
for i = 1; i < 50; i++ { |
||||
feSquare(&t2, &t2) |
||||
} |
||||
feMul(&t1, &t2, &t1) |
||||
feSquare(&t1, &t1) |
||||
for i = 1; i < 5; i++ { |
||||
feSquare(&t1, &t1) |
||||
} |
||||
feMul(out, &t1, &t0) |
||||
} |
||||
|
||||
func scalarMultGeneric(out, in, base *[32]byte) { |
||||
var e [32]byte |
||||
|
||||
copy(e[:], in[:]) |
||||
e[0] &= 248 |
||||
e[31] &= 127 |
||||
e[31] |= 64 |
||||
|
||||
var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement |
||||
feFromBytes(&x1, base) |
||||
feOne(&x2) |
||||
feCopy(&x3, &x1) |
||||
feOne(&z3) |
||||
|
||||
swap := int32(0) |
||||
for pos := 254; pos >= 0; pos-- { |
||||
b := e[pos/8] >> uint(pos&7) |
||||
b &= 1 |
||||
swap ^= int32(b) |
||||
feCSwap(&x2, &x3, swap) |
||||
feCSwap(&z2, &z3, swap) |
||||
swap = int32(b) |
||||
|
||||
feSub(&tmp0, &x3, &z3) |
||||
feSub(&tmp1, &x2, &z2) |
||||
feAdd(&x2, &x2, &z2) |
||||
feAdd(&z2, &x3, &z3) |
||||
feMul(&z3, &tmp0, &x2) |
||||
feMul(&z2, &z2, &tmp1) |
||||
feSquare(&tmp0, &tmp1) |
||||
feSquare(&tmp1, &x2) |
||||
feAdd(&x3, &z3, &z2) |
||||
feSub(&z2, &z3, &z2) |
||||
feMul(&x2, &tmp1, &tmp0) |
||||
feSub(&tmp1, &tmp1, &tmp0) |
||||
feSquare(&z2, &z2) |
||||
feMul121666(&z3, &tmp1) |
||||
feSquare(&x3, &x3) |
||||
feAdd(&tmp0, &tmp0, &z3) |
||||
feMul(&z3, &x1, &z2) |
||||
feMul(&z2, &tmp1, &tmp0) |
||||
} |
||||
|
||||
feCSwap(&x2, &x3, swap) |
||||
feCSwap(&z2, &z3, swap) |
||||
|
||||
feInvert(&z2, &z2) |
||||
feMul(&x2, &x2, &z2) |
||||
feToBytes(out, &x2) |
||||
} |
@ -0,0 +1,11 @@ |
||||
// Copyright 2019 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 appengine purego
|
||||
|
||||
package curve25519 |
||||
|
||||
func scalarMult(out, in, base *[32]byte) { |
||||
scalarMultGeneric(out, in, base) |
||||
} |
@ -1,23 +0,0 @@ |
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package curve25519 provides an implementation of scalar multiplication on
|
||||
// the elliptic curve known as curve25519. See https://cr.yp.to/ecdh.html
|
||||
package curve25519 // import "golang.org/x/crypto/curve25519"
|
||||
|
||||
// basePoint is the x coordinate of the generator of the curve.
|
||||
var basePoint = [32]byte{9, 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} |
||||
|
||||
// ScalarMult sets dst to the product in*base where dst and base are the x
|
||||
// coordinates of group points and all values are in little-endian form.
|
||||
func ScalarMult(dst, in, base *[32]byte) { |
||||
scalarMult(dst, in, base) |
||||
} |
||||
|
||||
// ScalarBaseMult sets dst to the product in*base where dst and base are the x
|
||||
// coordinates of group points, base is the standard generator and all values
|
||||
// are in little-endian form.
|
||||
func ScalarBaseMult(dst, in *[32]byte) { |
||||
ScalarMult(dst, in, &basePoint) |
||||
} |
@ -1,73 +0,0 @@ |
||||
// Copyright 2012 The Go Authors. All rights reserved. |
||||
// Use of this source code is governed by a BSD-style |
||||
// license that can be found in the LICENSE file. |
||||
|
||||
// This code was translated into a form compatible with 6a from the public |
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html |
||||
|
||||
// +build amd64,!gccgo,!appengine |
||||
|
||||
#include "const_amd64.h" |
||||
|
||||
// func freeze(inout *[5]uint64) |
||||
TEXT ·freeze(SB),7,$0-8 |
||||
MOVQ inout+0(FP), DI |
||||
|
||||
MOVQ 0(DI),SI |
||||
MOVQ 8(DI),DX |
||||
MOVQ 16(DI),CX |
||||
MOVQ 24(DI),R8 |
||||
MOVQ 32(DI),R9 |
||||
MOVQ $REDMASK51,AX |
||||
MOVQ AX,R10 |
||||
SUBQ $18,R10 |
||||
MOVQ $3,R11 |
||||
REDUCELOOP: |
||||
MOVQ SI,R12 |
||||
SHRQ $51,R12 |
||||
ANDQ AX,SI |
||||
ADDQ R12,DX |
||||
MOVQ DX,R12 |
||||
SHRQ $51,R12 |
||||
ANDQ AX,DX |
||||
ADDQ R12,CX |
||||
MOVQ CX,R12 |
||||
SHRQ $51,R12 |
||||
ANDQ AX,CX |
||||
ADDQ R12,R8 |
||||
MOVQ R8,R12 |
||||
SHRQ $51,R12 |
||||
ANDQ AX,R8 |
||||
ADDQ R12,R9 |
||||
MOVQ R9,R12 |
||||
SHRQ $51,R12 |
||||
ANDQ AX,R9 |
||||
IMUL3Q $19,R12,R12 |
||||
ADDQ R12,SI |
||||
SUBQ $1,R11 |
||||
JA REDUCELOOP |
||||
MOVQ $1,R12 |
||||
CMPQ R10,SI |
||||
CMOVQLT R11,R12 |
||||
CMPQ AX,DX |
||||
CMOVQNE R11,R12 |
||||
CMPQ AX,CX |
||||
CMOVQNE R11,R12 |
||||
CMPQ AX,R8 |
||||
CMOVQNE R11,R12 |
||||
CMPQ AX,R9 |
||||
CMOVQNE R11,R12 |
||||
NEGQ R12 |
||||
ANDQ R12,AX |
||||
ANDQ R12,R10 |
||||
SUBQ R10,SI |
||||
SUBQ AX,DX |
||||
SUBQ AX,CX |
||||
SUBQ AX,R8 |
||||
SUBQ AX,R9 |
||||
MOVQ SI,0(DI) |
||||
MOVQ DX,8(DI) |
||||
MOVQ CX,16(DI) |
||||
MOVQ R8,24(DI) |
||||
MOVQ R9,32(DI) |
||||
RET |
@ -1,169 +0,0 @@ |
||||
// Copyright 2012 The Go Authors. All rights reserved. |
||||
// Use of this source code is governed by a BSD-style |
||||
// license that can be found in the LICENSE file. |
||||
|
||||
// This code was translated into a form compatible with 6a from the public |
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html |
||||
|
||||
// +build amd64,!gccgo,!appengine |
||||
|
||||
#include "const_amd64.h" |
||||
|
||||
// func mul(dest, a, b *[5]uint64) |
||||
TEXT ·mul(SB),0,$16-24 |
||||
MOVQ dest+0(FP), DI |
||||
MOVQ a+8(FP), SI |
||||
MOVQ b+16(FP), DX |
||||
|
||||
MOVQ DX,CX |
||||
MOVQ 24(SI),DX |
||||
IMUL3Q $19,DX,AX |
||||
MOVQ AX,0(SP) |
||||
MULQ 16(CX) |
||||
MOVQ AX,R8 |
||||
MOVQ DX,R9 |
||||
MOVQ 32(SI),DX |
||||
IMUL3Q $19,DX,AX |
||||
MOVQ AX,8(SP) |
||||
MULQ 8(CX) |
||||
ADDQ AX,R8 |
||||
ADCQ DX,R9 |
||||
MOVQ 0(SI),AX |
||||
MULQ 0(CX) |
||||
ADDQ AX,R8 |
||||
ADCQ DX,R9 |
||||
MOVQ 0(SI),AX |
||||
MULQ 8(CX) |
||||
MOVQ AX,R10 |
||||
MOVQ DX,R11 |
||||
MOVQ 0(SI),AX |
||||
MULQ 16(CX) |
||||
MOVQ AX,R12 |
||||
MOVQ DX,R13 |
||||
MOVQ 0(SI),AX |
||||
MULQ 24(CX) |
||||
MOVQ AX,R14 |
||||
MOVQ DX,R15 |
||||
MOVQ 0(SI),AX |
||||
MULQ 32(CX) |
||||
MOVQ AX,BX |
||||
MOVQ DX,BP |
||||
MOVQ 8(SI),AX |
||||
MULQ 0(CX) |
||||
ADDQ AX,R10 |
||||
ADCQ DX,R11 |
||||
MOVQ 8(SI),AX |
||||
MULQ 8(CX) |
||||
ADDQ AX,R12 |
||||
ADCQ DX,R13 |
||||
MOVQ 8(SI),AX |
||||
MULQ 16(CX) |
||||
ADDQ AX,R14 |
||||
ADCQ DX,R15 |
||||
MOVQ 8(SI),AX |
||||
MULQ 24(CX) |
||||
ADDQ AX,BX |
||||
ADCQ DX,BP |
||||
MOVQ 8(SI),DX |
||||
IMUL3Q $19,DX,AX |
||||
MULQ 32(CX) |
||||
ADDQ AX,R8 |
||||
ADCQ DX,R9 |
||||
MOVQ 16(SI),AX |
||||
MULQ 0(CX) |
||||
ADDQ AX,R12 |
||||
ADCQ DX,R13 |
||||
MOVQ 16(SI),AX |
||||
MULQ 8(CX) |
||||
ADDQ AX,R14 |
||||
ADCQ DX,R15 |
||||
MOVQ 16(SI),AX |
||||
MULQ 16(CX) |
||||
ADDQ AX,BX |
||||
ADCQ DX,BP |
||||
MOVQ 16(SI),DX |
||||
IMUL3Q $19,DX,AX |
||||
MULQ 24(CX) |
||||
ADDQ AX,R8 |
||||
ADCQ DX,R9 |
||||
MOVQ 16(SI),DX |
||||
IMUL3Q $19,DX,AX |
||||
MULQ 32(CX) |
||||
ADDQ AX,R10 |
||||
ADCQ DX,R11 |
||||
MOVQ 24(SI),AX |
||||
MULQ 0(CX) |
||||
ADDQ AX,R14 |
||||
ADCQ DX,R15 |
||||
MOVQ 24(SI),AX |
||||
MULQ 8(CX) |
||||
ADDQ AX,BX |
||||
ADCQ DX,BP |
||||
MOVQ 0(SP),AX |
||||
MULQ 24(CX) |
||||
ADDQ AX,R10 |
||||
ADCQ DX,R11 |
||||
MOVQ 0(SP),AX |
||||
MULQ 32(CX) |
||||
ADDQ AX,R12 |
||||
ADCQ DX,R13 |
||||
MOVQ 32(SI),AX |
||||
MULQ 0(CX) |
||||
ADDQ AX,BX |
||||
ADCQ DX,BP |
||||
MOVQ 8(SP),AX |
||||
MULQ 16(CX) |
||||
ADDQ AX,R10 |
||||
ADCQ DX,R11 |
||||
MOVQ 8(SP),AX |
||||
MULQ 24(CX) |
||||
ADDQ AX,R12 |
||||
ADCQ DX,R13 |
||||
MOVQ 8(SP),AX |
||||
MULQ 32(CX) |
||||
ADDQ AX,R14 |
||||
ADCQ DX,R15 |
||||
MOVQ $REDMASK51,SI |
||||
SHLQ $13,R8,R9 |
||||
ANDQ SI,R8 |
||||
SHLQ $13,R10,R11 |
||||
ANDQ SI,R10 |
||||
ADDQ R9,R10 |
||||
SHLQ $13,R12,R13 |
||||
ANDQ SI,R12 |
||||
ADDQ R11,R12 |
||||
SHLQ $13,R14,R15 |
||||
ANDQ SI,R14 |
||||
ADDQ R13,R14 |
||||
SHLQ $13,BX,BP |
||||
ANDQ SI,BX |
||||
ADDQ R15,BX |
||||
IMUL3Q $19,BP,DX |
||||
ADDQ DX,R8 |
||||
MOVQ R8,DX |
||||
SHRQ $51,DX |
||||
ADDQ R10,DX |
||||
MOVQ DX,CX |
||||
SHRQ $51,DX |
||||
ANDQ SI,R8 |
||||
ADDQ R12,DX |
||||
MOVQ DX,R9 |
||||
SHRQ $51,DX |
||||
ANDQ SI,CX |
||||
ADDQ R14,DX |
||||
MOVQ DX,AX |
||||
SHRQ $51,DX |
||||
ANDQ SI,R9 |
||||
ADDQ BX,DX |
||||
MOVQ DX,R10 |
||||
SHRQ $51,DX |
||||
ANDQ SI,AX |
||||
IMUL3Q $19,DX,DX |
||||
ADDQ DX,R8 |
||||
ANDQ SI,R10 |
||||
MOVQ R8,0(DI) |
||||
MOVQ CX,8(DI) |
||||
MOVQ R9,16(DI) |
||||
MOVQ AX,24(DI) |
||||
MOVQ R10,32(DI) |
||||
RET |
@ -1,132 +0,0 @@ |
||||
// Copyright 2012 The Go Authors. All rights reserved. |
||||
// Use of this source code is governed by a BSD-style |
||||
// license that can be found in the LICENSE file. |
||||
|
||||
// This code was translated into a form compatible with 6a from the public |
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html |
||||
|
||||
// +build amd64,!gccgo,!appengine |
||||
|
||||
#include "const_amd64.h" |
||||
|
||||
// func square(out, in *[5]uint64) |
||||
TEXT ·square(SB),7,$0-16 |
||||
MOVQ out+0(FP), DI |
||||
MOVQ in+8(FP), SI |
||||
|
||||
MOVQ 0(SI),AX |
||||
MULQ 0(SI) |
||||
MOVQ AX,CX |
||||
MOVQ DX,R8 |
||||
MOVQ 0(SI),AX |
||||
SHLQ $1,AX |
||||
MULQ 8(SI) |
||||
MOVQ AX,R9 |
||||
MOVQ DX,R10 |
||||
MOVQ 0(SI),AX |
||||
SHLQ $1,AX |
||||
MULQ 16(SI) |
||||
MOVQ AX,R11 |
||||
MOVQ DX,R12 |
||||
MOVQ 0(SI),AX |
||||
SHLQ $1,AX |
||||
MULQ 24(SI) |
||||
MOVQ AX,R13 |
||||
MOVQ DX,R14 |
||||
MOVQ 0(SI),AX |
||||
SHLQ $1,AX |
||||
MULQ 32(SI) |
||||
MOVQ AX,R15 |
||||
MOVQ DX,BX |
||||
MOVQ 8(SI),AX |
||||
MULQ 8(SI) |
||||
ADDQ AX,R11 |
||||
ADCQ DX,R12 |
||||
MOVQ 8(SI),AX |
||||
SHLQ $1,AX |
||||
MULQ 16(SI) |
||||
ADDQ AX,R13 |
||||
ADCQ DX,R14 |
||||
MOVQ 8(SI),AX |
||||
SHLQ $1,AX |
||||
MULQ 24(SI) |
||||
ADDQ AX,R15 |
||||
ADCQ DX,BX |
||||
MOVQ 8(SI),DX |
||||
IMUL3Q $38,DX,AX |
||||
MULQ 32(SI) |
||||
ADDQ AX,CX |
||||
ADCQ DX,R8 |
||||
MOVQ 16(SI),AX |
||||
MULQ 16(SI) |
||||
ADDQ AX,R15 |
||||
ADCQ DX,BX |
||||
MOVQ 16(SI),DX |
||||
IMUL3Q $38,DX,AX |
||||
MULQ 24(SI) |
||||
ADDQ AX,CX |
||||
ADCQ DX,R8 |
||||
MOVQ 16(SI),DX |
||||
IMUL3Q $38,DX,AX |
||||
MULQ 32(SI) |
||||
ADDQ AX,R9 |
||||
ADCQ DX,R10 |
||||
MOVQ 24(SI),DX |
||||
IMUL3Q $19,DX,AX |
||||
MULQ 24(SI) |
||||
ADDQ AX,R9 |
||||
ADCQ DX,R10 |
||||
MOVQ 24(SI),DX |
||||
IMUL3Q $38,DX,AX |
||||
MULQ 32(SI) |
||||
ADDQ AX,R11 |
||||
ADCQ DX,R12 |
||||
MOVQ 32(SI),DX |
||||
IMUL3Q $19,DX,AX |
||||
MULQ 32(SI) |
||||
ADDQ AX,R13 |
||||
ADCQ DX,R14 |
||||
MOVQ $REDMASK51,SI |
||||
SHLQ $13,CX,R8 |
||||
ANDQ SI,CX |
||||
SHLQ $13,R9,R10 |
||||
ANDQ SI,R9 |
||||
ADDQ R8,R9 |
||||
SHLQ $13,R11,R12 |
||||
ANDQ SI,R11 |
||||
ADDQ R10,R11 |
||||
SHLQ $13,R13,R14 |
||||
ANDQ SI,R13 |
||||
ADDQ R12,R13 |
||||
SHLQ $13,R15,BX |
||||
ANDQ SI,R15 |
||||
ADDQ R14,R15 |
||||
IMUL3Q $19,BX,DX |
||||
ADDQ DX,CX |
||||
MOVQ CX,DX |
||||
SHRQ $51,DX |
||||
ADDQ R9,DX |
||||
ANDQ SI,CX |
||||
MOVQ DX,R8 |
||||
SHRQ $51,DX |
||||
ADDQ R11,DX |
||||
ANDQ SI,R8 |
||||
MOVQ DX,R9 |
||||
SHRQ $51,DX |
||||
ADDQ R13,DX |
||||
ANDQ SI,R9 |
||||
MOVQ DX,AX |
||||
SHRQ $51,DX |
||||
ADDQ R15,DX |
||||
ANDQ SI,AX |
||||
MOVQ DX,R10 |
||||
SHRQ $51,DX |
||||
IMUL3Q $19,DX,DX |
||||
ADDQ DX,CX |
||||
ANDQ SI,R10 |
||||
MOVQ CX,0(DI) |
||||
MOVQ R8,8(DI) |
||||
MOVQ R9,16(DI) |
||||
MOVQ AX,24(DI) |
||||
MOVQ R10,32(DI) |
||||
RET |
@ -1,668 +0,0 @@ |
||||
// Copyright 2019 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. |
||||
|
||||
// Based on CRYPTOGAMS code with the following comment: |
||||
// # ==================================================================== |
||||
// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
|
||||
// # project. The module is, however, dual licensed under OpenSSL and |
||||
// # CRYPTOGAMS licenses depending on where you obtain it. For further |
||||
// # details see http://www.openssl.org/~appro/cryptogams/. |
||||
// # ==================================================================== |
||||
|
||||
// Original code can be found at the link below: |
||||
// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91e5c39ca79126a4a876d5d8ff |
||||
|
||||
// There are some differences between CRYPTOGAMS code and this one. The round |
||||
// loop for "_int" isn't the same as the original. Some adjustments were |
||||
// necessary because there are less vector registers available. For example, some |
||||
// X variables (r12, r13, r14, and r15) share the same register used by the |
||||
// counter. The original code uses ctr to name the counter. Here we use CNT |
||||
// because golang uses CTR as the counter register name. |
||||
|
||||
// +build ppc64le,!gccgo,!appengine |
||||
|
||||
#include "textflag.h" |
||||
|
||||
#define OUT R3 |
||||
#define INP R4 |
||||
#define LEN R5 |
||||
#define KEY R6 |
||||
#define CNT R7 |
||||
|
||||
#define TEMP R8 |
||||
|
||||
#define X0 R11 |
||||
#define X1 R12 |
||||
#define X2 R14 |
||||
#define X3 R15 |
||||
#define X4 R16 |
||||
#define X5 R17 |
||||
#define X6 R18 |
||||
#define X7 R19 |
||||
#define X8 R20 |
||||
#define X9 R21 |
||||
#define X10 R22 |
||||
#define X11 R23 |
||||
#define X12 R24 |
||||
#define X13 R25 |
||||
#define X14 R26 |
||||
#define X15 R27 |
||||
|
||||
#define CON0 X0 |
||||
#define CON1 X1 |
||||
#define CON2 X2 |
||||
#define CON3 X3 |
||||
|
||||
#define KEY0 X4 |
||||
#define KEY1 X5 |
||||
#define KEY2 X6 |
||||
#define KEY3 X7 |
||||
#define KEY4 X8 |
||||
#define KEY5 X9 |
||||
#define KEY6 X10 |
||||
#define KEY7 X11 |
||||
|
||||
#define CNT0 X12 |
||||
#define CNT1 X13 |
||||
#define CNT2 X14 |
||||
#define CNT3 X15 |
||||
|
||||
#define TMP0 R9 |
||||
#define TMP1 R10 |
||||
#define TMP2 R28 |
||||
#define TMP3 R29 |
||||
|
||||
#define CONSTS R8 |
||||
|
||||
#define A0 V0 |
||||
#define B0 V1 |
||||
#define C0 V2 |
||||
#define D0 V3 |
||||
#define A1 V4 |
||||
#define B1 V5 |
||||
#define C1 V6 |
||||
#define D1 V7 |
||||
#define A2 V8 |
||||
#define B2 V9 |
||||
#define C2 V10 |
||||
#define D2 V11 |
||||
#define T0 V12 |
||||
#define T1 V13 |
||||
#define T2 V14 |
||||
|
||||
#define K0 V15 |
||||
#define K1 V16 |
||||
#define K2 V17 |
||||
#define K3 V18 |
||||
#define K4 V19 |
||||
#define K5 V20 |
||||
|
||||
#define FOUR V21 |
||||
#define SIXTEEN V22 |
||||
#define TWENTY4 V23 |
||||
#define TWENTY V24 |
||||
#define TWELVE V25 |
||||
#define TWENTY5 V26 |
||||
#define SEVEN V27 |
||||
|
||||
#define INPPERM V28 |
||||
#define OUTPERM V29 |
||||
#define OUTMASK V30 |
||||
|
||||
#define DD0 V31 |
||||
#define DD1 SEVEN |
||||
#define DD2 T0 |
||||
#define DD3 T1 |
||||
#define DD4 T2 |
||||
|
||||
DATA ·consts+0x00(SB)/8, $0x3320646e61707865 |
||||
DATA ·consts+0x08(SB)/8, $0x6b20657479622d32 |
||||
DATA ·consts+0x10(SB)/8, $0x0000000000000001 |
||||
DATA ·consts+0x18(SB)/8, $0x0000000000000000 |
||||
DATA ·consts+0x20(SB)/8, $0x0000000000000004 |
||||
DATA ·consts+0x28(SB)/8, $0x0000000000000000 |
||||
DATA ·consts+0x30(SB)/8, $0x0a0b08090e0f0c0d |
||||
DATA ·consts+0x38(SB)/8, $0x0203000106070405 |
||||
DATA ·consts+0x40(SB)/8, $0x090a0b080d0e0f0c |
||||
DATA ·consts+0x48(SB)/8, $0x0102030005060704 |
||||
GLOBL ·consts(SB), RODATA, $80 |
||||
|
||||
//func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[32]byte, counter *[16]byte) |
||||
TEXT ·chaCha20_ctr32_vmx(SB),NOSPLIT|NOFRAME,$0 |
||||
// Load the arguments inside the registers |
||||
MOVD out+0(FP), OUT |
||||
MOVD inp+8(FP), INP |
||||
MOVD len+16(FP), LEN |
||||
MOVD key+24(FP), KEY |
||||
MOVD counter+32(FP), CNT |
||||
|
||||
MOVD $·consts(SB), CONSTS // point to consts addr |
||||
|
||||
MOVD $16, X0 |
||||
MOVD $32, X1 |
||||
MOVD $48, X2 |
||||
MOVD $64, X3 |
||||
MOVD $31, X4 |
||||
MOVD $15, X5 |
||||
|
||||
// Load key |
||||
LVX (KEY)(R0), K1 |
||||
LVSR (KEY)(R0), T0 |
||||
LVX (KEY)(X0), K2 |
||||
LVX (KEY)(X4), DD0 |
||||
|
||||
// Load counter |
||||
LVX (CNT)(R0), K3 |
||||
LVSR (CNT)(R0), T1 |
||||
LVX (CNT)(X5), DD1 |
||||
|
||||
// Load constants |
||||
LVX (CONSTS)(R0), K0 |
||||
LVX (CONSTS)(X0), K5 |
||||
LVX (CONSTS)(X1), FOUR |
||||
LVX (CONSTS)(X2), SIXTEEN |
||||
LVX (CONSTS)(X3), TWENTY4 |
||||
|
||||
// Align key and counter |
||||
VPERM K2, K1, T0, K1 |
||||
VPERM DD0, K2, T0, K2 |
||||
VPERM DD1, K3, T1, K3 |
||||
|
||||
// Load counter to GPR |
||||
MOVWZ 0(CNT), CNT0 |
||||
MOVWZ 4(CNT), CNT1 |
||||
MOVWZ 8(CNT), CNT2 |
||||
MOVWZ 12(CNT), CNT3 |
||||
|
||||
// Adjust vectors for the initial state |
||||
VADDUWM K3, K5, K3 |
||||
VADDUWM K3, K5, K4 |
||||
VADDUWM K4, K5, K5 |
||||
|
||||
// Synthesized constants |
||||
VSPLTISW $-12, TWENTY |
||||
VSPLTISW $12, TWELVE |
||||
VSPLTISW $-7, TWENTY5 |
||||
|
||||
VXOR T0, T0, T0 |
||||
VSPLTISW $-1, OUTMASK |
||||
LVSR (INP)(R0), INPPERM |
||||
LVSL (OUT)(R0), OUTPERM |
||||
VPERM OUTMASK, T0, OUTPERM, OUTMASK |
||||
|
||||
loop_outer_vmx: |
||||
// Load constant |
||||
MOVD $0x61707865, CON0 |
||||
MOVD $0x3320646e, CON1 |
||||
MOVD $0x79622d32, CON2 |
||||
MOVD $0x6b206574, CON3 |
||||
|
||||
VOR K0, K0, A0 |
||||
VOR K0, K0, A1 |
||||
VOR K0, K0, A2 |
||||
VOR K1, K1, B0 |
||||
|
||||
MOVD $10, TEMP |
||||
|
||||
// Load key to GPR |
||||
MOVWZ 0(KEY), X4 |
||||
MOVWZ 4(KEY), X5 |
||||
MOVWZ 8(KEY), X6 |
||||
MOVWZ 12(KEY), X7 |
||||
VOR K1, K1, B1 |
||||
VOR K1, K1, B2 |
||||
MOVWZ 16(KEY), X8 |
||||
MOVWZ 0(CNT), X12 |
||||
MOVWZ 20(KEY), X9 |
||||
MOVWZ 4(CNT), X13 |
||||
VOR K2, K2, C0 |
||||
VOR K2, K2, C1 |
||||
MOVWZ 24(KEY), X10 |
||||
MOVWZ 8(CNT), X14 |
||||
VOR K2, K2, C2 |
||||
VOR K3, K3, D0 |
||||
MOVWZ 28(KEY), X11 |
||||
MOVWZ 12(CNT), X15 |
||||
VOR K4, K4, D1 |
||||
VOR K5, K5, D2 |
||||
|
||||
MOVD X4, TMP0 |
||||
MOVD X5, TMP1 |
||||
MOVD X6, TMP2 |
||||
MOVD X7, TMP3 |
||||
VSPLTISW $7, SEVEN |
||||
|
||||
MOVD TEMP, CTR |
||||
|
||||
loop_vmx: |
||||
// CRYPTOGAMS uses a macro to create a loop using perl. This isn't possible |
||||
// using assembly macros. Therefore, the macro expansion result was used |
||||
// in order to maintain the algorithm efficiency. |
||||
// This loop generates three keystream blocks using VMX instructions and, |
||||
// in parallel, one keystream block using scalar instructions. |
||||
ADD X4, X0, X0 |
||||
ADD X5, X1, X1 |
||||
VADDUWM A0, B0, A0 |
||||
VADDUWM A1, B1, A1 |
||||
ADD X6, X2, X2 |
||||
ADD X7, X3, X3 |
||||
VADDUWM A2, B2, A2 |
||||
VXOR D0, A0, D0 |
||||
XOR X0, X12, X12 |
||||
XOR X1, X13, X13 |
||||
VXOR D1, A1, D1 |
||||
VXOR D2, A2, D2 |
||||
XOR X2, X14, X14 |
||||
XOR X3, X15, X15 |
||||
VPERM D0, D0, SIXTEEN, D0 |
||||
VPERM D1, D1, SIXTEEN, D1 |
||||
ROTLW $16, X12, X12 |
||||
ROTLW $16, X13, X13 |
||||
VPERM D2, D2, SIXTEEN, D2 |
||||
VADDUWM C0, D0, C0 |
||||
ROTLW $16, X14, X14 |
||||
ROTLW $16, X15, X15 |
||||
VADDUWM C1, D1, C1 |
||||
VADDUWM C2, D2, C2 |
||||
ADD X12, X8, X8 |
||||
ADD X13, X9, X9 |
||||
VXOR B0, C0, T0 |
||||
VXOR B1, C1, T1 |
||||
ADD X14, X10, X10 |
||||
ADD X15, X11, X11 |
||||
VXOR B2, C2, T2 |
||||
VRLW T0, TWELVE, B0 |
||||
XOR X8, X4, X4 |
||||
XOR X9, X5, X5 |
||||
VRLW T1, TWELVE, B1 |
||||
VRLW T2, TWELVE, B2 |
||||
XOR X10, X6, X6 |
||||
XOR X11, X7, X7 |
||||
VADDUWM A0, B0, A0 |
||||
VADDUWM A1, B1, A1 |
||||
ROTLW $12, X4, X4 |
||||
ROTLW $12, X5, X5 |
||||
VADDUWM A2, B2, A2 |
||||
VXOR D0, A0, D0 |
||||
ROTLW $12, X6, X6 |
||||
ROTLW $12, X7, X7 |
||||
VXOR D1, A1, D1 |
||||
VXOR D2, A2, D2 |
||||
ADD X4, X0, X0 |
||||
ADD X5, X1, X1 |
||||
VPERM D0, D0, TWENTY4, D0 |
||||
VPERM D1, D1, TWENTY4, D1 |
||||
ADD X6, X2, X2 |
||||
ADD X7, X3, X3 |
||||
VPERM D2, D2, TWENTY4, D2 |
||||
VADDUWM C0, D0, C0 |
||||
XOR X0, X12, X12 |
||||
XOR X1, X13, X13 |
||||
VADDUWM C1, D1, C1 |
||||
VADDUWM C2, D2, C2 |
||||
XOR X2, X14, X14 |
||||
XOR X3, X15, X15 |
||||
VXOR B0, C0, T0 |
||||
VXOR B1, C1, T1 |
||||
ROTLW $8, X12, X12 |
||||
ROTLW $8, X13, X13 |
||||
VXOR B2, C2, T2 |
||||
VRLW T0, SEVEN, B0 |
||||
ROTLW $8, X14, X14 |
||||
ROTLW $8, X15, X15 |
||||
VRLW T1, SEVEN, B1 |
||||
VRLW T2, SEVEN, B2 |
||||
ADD X12, X8, X8 |
||||
ADD X13, X9, X9 |
||||
VSLDOI $8, C0, C0, C0 |
||||
VSLDOI $8, C1, C1, C1 |
||||
ADD X14, X10, X10 |
||||
ADD X15, X11, X11 |
||||
VSLDOI $8, C2, C2, C2 |
||||
VSLDOI $12, B0, B0, B0 |
||||
XOR X8, X4, X4 |
||||
XOR X9, X5, X5 |
||||
VSLDOI $12, B1, B1, B1 |
||||
VSLDOI $12, B2, B2, B2 |
||||
XOR X10, X6, X6 |
||||
XOR X11, X7, X7 |
||||
VSLDOI $4, D0, D0, D0 |
||||
VSLDOI $4, D1, D1, D1 |
||||
ROTLW $7, X4, X4 |
||||
ROTLW $7, X5, X5 |
||||
VSLDOI $4, D2, D2, D2 |
||||
VADDUWM A0, B0, A0 |
||||
ROTLW $7, X6, X6 |
||||
ROTLW $7, X7, X7 |
||||
VADDUWM A1, B1, A1 |
||||
VADDUWM A2, B2, A2 |
||||
ADD X5, X0, X0 |
||||
ADD X6, X1, X1 |
||||
VXOR D0, A0, D0 |
||||
VXOR D1, A1, D1 |
||||
ADD X7, X2, X2 |
||||
ADD X4, X3, X3 |
||||
VXOR D2, A2, D2 |
||||
VPERM D0, D0, SIXTEEN, D0 |
||||
XOR X0, X15, X15 |
||||
XOR X1, X12, X12 |
||||
VPERM D1, D1, SIXTEEN, D1 |
||||
VPERM D2, D2, SIXTEEN, D2 |
||||
XOR X2, X13, X13 |
||||
XOR X3, X14, X14 |
||||
VADDUWM C0, D0, C0 |
||||
VADDUWM C1, D1, C1 |
||||
ROTLW $16, X15, X15 |
||||
ROTLW $16, X12, X12 |
||||
VADDUWM C2, D2, C2 |
||||
VXOR B0, C0, T0 |
||||
ROTLW $16, X13, X13 |
||||
ROTLW $16, X14, X14 |
||||
VXOR B1, C1, T1 |
||||
VXOR B2, C2, T2 |
||||
ADD X15, X10, X10 |
||||
ADD X12, X11, X11 |
||||
VRLW T0, TWELVE, B0 |
||||
VRLW T1, TWELVE, B1 |
||||
ADD X13, X8, X8 |
||||
ADD X14, X9, X9 |
||||
VRLW T2, TWELVE, B2 |
||||
VADDUWM A0, B0, A0 |
||||
XOR X10, X5, X5 |
||||
XOR X11, X6, X6 |
||||
VADDUWM A1, B1, A1 |
||||
VADDUWM A2, B2, A2 |
||||
XOR X8, X7, X7 |
||||
XOR X9, X4, X4 |
||||
VXOR D0, A0, D0 |
||||
VXOR D1, A1, D1 |
||||
ROTLW $12, X5, X5 |
||||
ROTLW $12, X6, X6 |
||||
VXOR D2, A2, D2 |
||||
VPERM D0, D0, TWENTY4, D0 |
||||
ROTLW $12, X7, X7 |
||||
ROTLW $12, X4, X4 |
||||
VPERM D1, D1, TWENTY4, D1 |
||||
VPERM D2, D2, TWENTY4, D2 |
||||
ADD X5, X0, X0 |
||||
ADD X6, X1, X1 |
||||
VADDUWM C0, D0, C0 |
||||
VADDUWM C1, D1, C1 |
||||
ADD X7, X2, X2 |
||||
ADD X4, X3, X3 |
||||
VADDUWM C2, D2, C2 |
||||
VXOR B0, C0, T0 |
||||
XOR X0, X15, X15 |
||||
XOR X1, X12, X12 |
||||
VXOR B1, C1, T1 |
||||
VXOR B2, C2, T2 |
||||
XOR X2, X13, X13 |
||||
XOR X3, X14, X14 |
||||
VRLW T0, SEVEN, B0 |
||||
VRLW T1, SEVEN, B1 |
||||
ROTLW $8, X15, X15 |
||||
ROTLW $8, X12, X12 |
||||
VRLW T2, SEVEN, B2 |
||||
VSLDOI $8, C0, C0, C0 |
||||
ROTLW $8, X13, X13 |
||||
ROTLW $8, X14, X14 |
||||
VSLDOI $8, C1, C1, C1 |
||||
VSLDOI $8, C2, C2, C2 |
||||
ADD X15, X10, X10 |
||||
ADD X12, X11, X11 |
||||
VSLDOI $4, B0, B0, B0 |
||||
VSLDOI $4, B1, B1, B1 |
||||
ADD X13, X8, X8 |
||||
ADD X14, X9, X9 |
||||
VSLDOI $4, B2, B2, B2 |
||||
VSLDOI $12, D0, D0, D0 |
||||
XOR X10, X5, X5 |
||||
XOR X11, X6, X6 |
||||
VSLDOI $12, D1, D1, D1 |
||||
VSLDOI $12, D2, D2, D2 |
||||
XOR X8, X7, X7 |
||||
XOR X9, X4, X4 |
||||
ROTLW $7, X5, X5 |
||||
ROTLW $7, X6, X6 |
||||
ROTLW $7, X7, X7 |
||||
ROTLW $7, X4, X4 |
||||
BC 0x10, 0, loop_vmx |
||||
|
||||
SUB $256, LEN, LEN |
||||
|
||||
// Accumulate key block |
||||
ADD $0x61707865, X0, X0 |
||||
ADD $0x3320646e, X1, X1 |
||||
ADD $0x79622d32, X2, X2 |
||||
ADD $0x6b206574, X3, X3 |
||||
ADD TMP0, X4, X4 |
||||
ADD TMP1, X5, X5 |
||||
ADD TMP2, X6, X6 |
||||
ADD TMP3, X7, X7 |
||||
MOVWZ 16(KEY), TMP0 |
||||
MOVWZ 20(KEY), TMP1 |
||||
MOVWZ 24(KEY), TMP2 |
||||
MOVWZ 28(KEY), TMP3 |
||||
ADD TMP0, X8, X8 |
||||
ADD TMP1, X9, X9 |
||||
ADD TMP2, X10, X10 |
||||
ADD TMP3, X11, X11 |
||||
|
||||
MOVWZ 12(CNT), TMP0 |
||||
MOVWZ 8(CNT), TMP1 |
||||
MOVWZ 4(CNT), TMP2 |
||||
MOVWZ 0(CNT), TEMP |
||||
ADD TMP0, X15, X15 |
||||
ADD TMP1, X14, X14 |
||||
ADD TMP2, X13, X13 |
||||
ADD TEMP, X12, X12 |
||||
|
||||
// Accumulate key block |
||||
VADDUWM A0, K0, A0 |
||||
VADDUWM A1, K0, A1 |
||||
VADDUWM A2, K0, A2 |
||||
VADDUWM B0, K1, B0 |
||||
VADDUWM B1, K1, B1 |
||||
VADDUWM B2, K1, B2 |
||||
VADDUWM C0, K2, C0 |
||||
VADDUWM C1, K2, C1 |
||||
VADDUWM C2, K2, C2 |
||||
VADDUWM D0, K3, D0 |
||||
VADDUWM D1, K4, D1 |
||||
VADDUWM D2, K5, D2 |
||||
|
||||
// Increment counter |
||||
ADD $4, TEMP, TEMP |
||||
MOVW TEMP, 0(CNT) |
||||
|
||||
VADDUWM K3, FOUR, K3 |
||||
VADDUWM K4, FOUR, K4 |
||||
VADDUWM K5, FOUR, K5 |
||||
|
||||
// XOR the input slice (INP) with the keystream, which is stored in GPRs (X0-X3). |
||||
|
||||
// Load input (aligned or not) |
||||
MOVWZ 0(INP), TMP0 |
||||
MOVWZ 4(INP), TMP1 |
||||
MOVWZ 8(INP), TMP2 |
||||
MOVWZ 12(INP), TMP3 |
||||
|
||||
// XOR with input |
||||
XOR TMP0, X0, X0 |
||||
XOR TMP1, X1, X1 |
||||
XOR TMP2, X2, X2 |
||||
XOR TMP3, X3, X3 |
||||
MOVWZ 16(INP), TMP0 |
||||
MOVWZ 20(INP), TMP1 |
||||
MOVWZ 24(INP), TMP2 |
||||
MOVWZ 28(INP), TMP3 |
||||
XOR TMP0, X4, X4 |
||||
XOR TMP1, X5, X5 |
||||
XOR TMP2, X6, X6 |
||||
XOR TMP3, X7, X7 |
||||
MOVWZ 32(INP), TMP0 |
||||
MOVWZ 36(INP), TMP1 |
||||
MOVWZ 40(INP), TMP2 |
||||
MOVWZ 44(INP), TMP3 |
||||
XOR TMP0, X8, X8 |
||||
XOR TMP1, X9, X9 |
||||
XOR TMP2, X10, X10 |
||||
XOR TMP3, X11, X11 |
||||
MOVWZ 48(INP), TMP0 |
||||
MOVWZ 52(INP), TMP1 |
||||
MOVWZ 56(INP), TMP2 |
||||
MOVWZ 60(INP), TMP3 |
||||
XOR TMP0, X12, X12 |
||||
XOR TMP1, X13, X13 |
||||
XOR TMP2, X14, X14 |
||||
XOR TMP3, X15, X15 |
||||
|
||||
// Store output (aligned or not) |
||||
MOVW X0, 0(OUT) |
||||
MOVW X1, 4(OUT) |
||||
MOVW X2, 8(OUT) |
||||
MOVW X3, 12(OUT) |
||||
|
||||
ADD $64, INP, INP // INP points to the end of the slice for the alignment code below |
||||
|
||||
MOVW X4, 16(OUT) |
||||
MOVD $16, TMP0 |
||||
MOVW X5, 20(OUT) |
||||
MOVD $32, TMP1 |
||||
MOVW X6, 24(OUT) |
||||
MOVD $48, TMP2 |
||||
MOVW X7, 28(OUT) |
||||
MOVD $64, TMP3 |
||||
MOVW X8, 32(OUT) |
||||
MOVW X9, 36(OUT) |
||||
MOVW X10, 40(OUT) |
||||
MOVW X11, 44(OUT) |
||||
MOVW X12, 48(OUT) |
||||
MOVW X13, 52(OUT) |
||||
MOVW X14, 56(OUT) |
||||
MOVW X15, 60(OUT) |
||||
ADD $64, OUT, OUT |
||||
|
||||
// Load input |
||||
LVX (INP)(R0), DD0 |
||||
LVX (INP)(TMP0), DD1 |
||||
LVX (INP)(TMP1), DD2 |
||||
LVX (INP)(TMP2), DD3 |
||||
LVX (INP)(TMP3), DD4 |
||||
ADD $64, INP, INP |
||||
|
||||
VPERM DD1, DD0, INPPERM, DD0 // Align input |
||||
VPERM DD2, DD1, INPPERM, DD1 |
||||
VPERM DD3, DD2, INPPERM, DD2 |
||||
VPERM DD4, DD3, INPPERM, DD3 |
||||
VXOR A0, DD0, A0 // XOR with input |
||||
VXOR B0, DD1, B0 |
||||
LVX (INP)(TMP0), DD1 // Keep loading input |
||||
VXOR C0, DD2, C0 |
||||
LVX (INP)(TMP1), DD2 |
||||
VXOR D0, DD3, D0 |
||||
LVX (INP)(TMP2), DD3 |
||||
LVX (INP)(TMP3), DD0 |
||||
ADD $64, INP, INP |
||||
MOVD $63, TMP3 // 63 is not a typo |
||||
VPERM A0, A0, OUTPERM, A0 |
||||
VPERM B0, B0, OUTPERM, B0 |
||||
VPERM C0, C0, OUTPERM, C0 |
||||
VPERM D0, D0, OUTPERM, D0 |
||||
|
||||
VPERM DD1, DD4, INPPERM, DD4 // Align input |
||||
VPERM DD2, DD1, INPPERM, DD1 |
||||
VPERM DD3, DD2, INPPERM, DD2 |
||||
VPERM DD0, DD3, INPPERM, DD3 |
||||
VXOR A1, DD4, A1 |
||||
VXOR B1, DD1, B1 |
||||
LVX (INP)(TMP0), DD1 // Keep loading |
||||
VXOR C1, DD2, C1 |
||||
LVX (INP)(TMP1), DD2 |
||||
VXOR D1, DD3, D1 |
||||
LVX (INP)(TMP2), DD3 |
||||
|
||||
// Note that the LVX address is always rounded down to the nearest 16-byte |
||||
// boundary, and that it always points to at most 15 bytes beyond the end of |
||||
// the slice, so we cannot cross a page boundary. |
||||
LVX (INP)(TMP3), DD4 // Redundant in aligned case. |
||||
ADD $64, INP, INP |
||||
VPERM A1, A1, OUTPERM, A1 // Pre-misalign output |
||||
VPERM B1, B1, OUTPERM, B1 |
||||
VPERM C1, C1, OUTPERM, C1 |
||||
VPERM D1, D1, OUTPERM, D1 |
||||
|
||||
VPERM DD1, DD0, INPPERM, DD0 // Align Input |
||||
VPERM DD2, DD1, INPPERM, DD1 |
||||
VPERM DD3, DD2, INPPERM, DD2 |
||||
VPERM DD4, DD3, INPPERM, DD3 |
||||
VXOR A2, DD0, A2 |
||||
VXOR B2, DD1, B2 |
||||
VXOR C2, DD2, C2 |
||||
VXOR D2, DD3, D2 |
||||
VPERM A2, A2, OUTPERM, A2 |
||||
VPERM B2, B2, OUTPERM, B2 |
||||
VPERM C2, C2, OUTPERM, C2 |
||||
VPERM D2, D2, OUTPERM, D2 |
||||
|
||||
ANDCC $15, OUT, X1 // Is out aligned? |
||||
MOVD OUT, X0 |
||||
|
||||
VSEL A0, B0, OUTMASK, DD0 // Collect pre-misaligned output |
||||
VSEL B0, C0, OUTMASK, DD1 |
||||
VSEL C0, D0, OUTMASK, DD2 |
||||
VSEL D0, A1, OUTMASK, DD3 |
||||
VSEL A1, B1, OUTMASK, B0 |
||||
VSEL B1, C1, OUTMASK, C0 |
||||
VSEL C1, D1, OUTMASK, D0 |
||||
VSEL D1, A2, OUTMASK, A1 |
||||
VSEL A2, B2, OUTMASK, B1 |
||||
VSEL B2, C2, OUTMASK, C1 |
||||
VSEL C2, D2, OUTMASK, D1 |
||||
|
||||
STVX DD0, (OUT+TMP0) |
||||
STVX DD1, (OUT+TMP1) |
||||
STVX DD2, (OUT+TMP2) |
||||
ADD $64, OUT, OUT |
||||
STVX DD3, (OUT+R0) |
||||
STVX B0, (OUT+TMP0) |
||||
STVX C0, (OUT+TMP1) |
||||
STVX D0, (OUT+TMP2) |
||||
ADD $64, OUT, OUT |
||||
STVX A1, (OUT+R0) |
||||
STVX B1, (OUT+TMP0) |
||||
STVX C1, (OUT+TMP1) |
||||
STVX D1, (OUT+TMP2) |
||||
ADD $64, OUT, OUT |
||||
|
||||
BEQ aligned_vmx |
||||
|
||||
SUB X1, OUT, X2 // in misaligned case edges |
||||
MOVD $0, X3 // are written byte-by-byte |
||||
|
||||
unaligned_tail_vmx: |
||||
STVEBX D2, (X2+X3) |
||||
ADD $1, X3, X3 |
||||
CMPW X3, X1 |
||||
BNE unaligned_tail_vmx |
||||
SUB X1, X0, X2 |
||||
|
||||
unaligned_head_vmx: |
||||
STVEBX A0, (X2+X1) |
||||
CMPW X1, $15 |
||||
ADD $1, X1, X1 |
||||
BNE unaligned_head_vmx |
||||
|
||||
CMPU LEN, $255 // done with 256-byte block yet? |
||||
BGT loop_outer_vmx |
||||
|
||||
JMP done_vmx |
||||
|
||||
aligned_vmx: |
||||
STVX A0, (X0+R0) |
||||
CMPU LEN, $255 // done with 256-byte block yet? |
||||
BGT loop_outer_vmx |
||||
|
||||
done_vmx: |
||||
RET |
@ -1,31 +0,0 @@ |
||||
// 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.
|
||||
|
||||
// +build go1.11
|
||||
// +build !gccgo
|
||||
|
||||
package chacha20 |
||||
|
||||
const ( |
||||
haveAsm = true |
||||
bufSize = 256 |
||||
) |
||||
|
||||
//go:noescape
|
||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) |
||||
|
||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) { |
||||
|
||||
if len(src) >= bufSize { |
||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter) |
||||
} |
||||
|
||||
if len(src)%bufSize != 0 { |
||||
i := len(src) - len(src)%bufSize |
||||
c.buf = [bufSize]byte{} |
||||
copy(c.buf[:], src[i:]) |
||||
xorKeyStreamVX(c.buf[:], c.buf[:], &c.key, &c.nonce, &c.counter) |
||||
c.len = bufSize - copy(dst[i:], c.buf[:len(src)%bufSize]) |
||||
} |
||||
} |
@ -1,264 +0,0 @@ |
||||
// 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 ChaCha20 implements the core ChaCha20 function as specified
|
||||
// in https://tools.ietf.org/html/rfc7539#section-2.3.
|
||||
package chacha20 |
||||
|
||||
import ( |
||||
"crypto/cipher" |
||||
"encoding/binary" |
||||
|
||||
"golang.org/x/crypto/internal/subtle" |
||||
) |
||||
|
||||
// assert that *Cipher implements cipher.Stream
|
||||
var _ cipher.Stream = (*Cipher)(nil) |
||||
|
||||
// Cipher is a stateful instance of ChaCha20 using a particular key
|
||||
// and nonce. A *Cipher implements the cipher.Stream interface.
|
||||
type Cipher struct { |
||||
key [8]uint32 |
||||
counter uint32 // incremented after each block
|
||||
nonce [3]uint32 |
||||
buf [bufSize]byte // buffer for unused keystream bytes
|
||||
len int // number of unused keystream bytes at end of buf
|
||||
} |
||||
|
||||
// New creates a new ChaCha20 stream cipher with the given key and nonce.
|
||||
// The initial counter value is set to 0.
|
||||
func New(key [8]uint32, nonce [3]uint32) *Cipher { |
||||
return &Cipher{key: key, nonce: nonce} |
||||
} |
||||
|
||||
// ChaCha20 constants spelling "expand 32-byte k"
|
||||
const ( |
||||
j0 uint32 = 0x61707865 |
||||
j1 uint32 = 0x3320646e |
||||
j2 uint32 = 0x79622d32 |
||||
j3 uint32 = 0x6b206574 |
||||
) |
||||
|
||||
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) { |
||||
a += b |
||||
d ^= a |
||||
d = (d << 16) | (d >> 16) |
||||
c += d |
||||
b ^= c |
||||
b = (b << 12) | (b >> 20) |
||||
a += b |
||||
d ^= a |
||||
d = (d << 8) | (d >> 24) |
||||
c += d |
||||
b ^= c |
||||
b = (b << 7) | (b >> 25) |
||||
return a, b, c, d |
||||
} |
||||
|
||||
// XORKeyStream XORs each byte in the given slice with a byte from the
|
||||
// cipher's key stream. Dst and src must overlap entirely or not at all.
|
||||
//
|
||||
// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
|
||||
// to pass a dst bigger than src, and in that case, XORKeyStream will
|
||||
// only update dst[:len(src)] and will not touch the rest of dst.
|
||||
//
|
||||
// Multiple calls to XORKeyStream behave as if the concatenation of
|
||||
// the src buffers was passed in a single run. That is, Cipher
|
||||
// maintains state and does not reset at each XORKeyStream call.
|
||||
func (s *Cipher) XORKeyStream(dst, src []byte) { |
||||
if len(dst) < len(src) { |
||||
panic("chacha20: output smaller than input") |
||||
} |
||||
if subtle.InexactOverlap(dst[:len(src)], src) { |
||||
panic("chacha20: invalid buffer overlap") |
||||
} |
||||
|
||||
// xor src with buffered keystream first
|
||||
if s.len != 0 { |
||||
buf := s.buf[len(s.buf)-s.len:] |
||||
if len(src) < len(buf) { |
||||
buf = buf[:len(src)] |
||||
} |
||||
td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
|
||||
for i, b := range buf { |
||||
td[i] = ts[i] ^ b |
||||
} |
||||
s.len -= len(buf) |
||||
if s.len != 0 { |
||||
return |
||||
} |
||||
s.buf = [len(s.buf)]byte{} // zero the empty buffer
|
||||
src = src[len(buf):] |
||||
dst = dst[len(buf):] |
||||
} |
||||
|
||||
if len(src) == 0 { |
||||
return |
||||
} |
||||
if haveAsm { |
||||
if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 { |
||||
panic("chacha20: counter overflow") |
||||
} |
||||
s.xorKeyStreamAsm(dst, src) |
||||
return |
||||
} |
||||
|
||||
// set up a 64-byte buffer to pad out the final block if needed
|
||||
// (hoisted out of the main loop to avoid spills)
|
||||
rem := len(src) % 64 // length of final block
|
||||
fin := len(src) - rem // index of final block
|
||||
if rem > 0 { |
||||
copy(s.buf[len(s.buf)-64:], src[fin:]) |
||||
} |
||||
|
||||
// pre-calculate most of the first round
|
||||
s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0]) |
||||
s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1]) |
||||
s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2]) |
||||
|
||||
n := len(src) |
||||
src, dst = src[:n:n], dst[:n:n] // BCE hint
|
||||
for i := 0; i < n; i += 64 { |
||||
// calculate the remainder of the first round
|
||||
s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter) |
||||
|
||||
// execute the second round
|
||||
x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15) |
||||
x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12) |
||||
x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13) |
||||
x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14) |
||||
|
||||
// execute the remaining 18 rounds
|
||||
for i := 0; i < 9; i++ { |
||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) |
||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) |
||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) |
||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) |
||||
|
||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) |
||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) |
||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) |
||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) |
||||
} |
||||
|
||||
x0 += j0 |
||||
x1 += j1 |
||||
x2 += j2 |
||||
x3 += j3 |
||||
|
||||
x4 += s.key[0] |
||||
x5 += s.key[1] |
||||
x6 += s.key[2] |
||||
x7 += s.key[3] |
||||
x8 += s.key[4] |
||||
x9 += s.key[5] |
||||
x10 += s.key[6] |
||||
x11 += s.key[7] |
||||
|
||||
x12 += s.counter |
||||
x13 += s.nonce[0] |
||||
x14 += s.nonce[1] |
||||
x15 += s.nonce[2] |
||||
|
||||
// increment the counter
|
||||
s.counter += 1 |
||||
if s.counter == 0 { |
||||
panic("chacha20: counter overflow") |
||||
} |
||||
|
||||
// pad to 64 bytes if needed
|
||||
in, out := src[i:], dst[i:] |
||||
if i == fin { |
||||
// src[fin:] has already been copied into s.buf before
|
||||
// the main loop
|
||||
in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:] |
||||
} |
||||
in, out = in[:64], out[:64] // BCE hint
|
||||
|
||||
// XOR the key stream with the source and write out the result
|
||||
xor(out[0:], in[0:], x0) |
||||
xor(out[4:], in[4:], x1) |
||||
xor(out[8:], in[8:], x2) |
||||
xor(out[12:], in[12:], x3) |
||||
xor(out[16:], in[16:], x4) |
||||
xor(out[20:], in[20:], x5) |
||||
xor(out[24:], in[24:], x6) |
||||
xor(out[28:], in[28:], x7) |
||||
xor(out[32:], in[32:], x8) |
||||
xor(out[36:], in[36:], x9) |
||||
xor(out[40:], in[40:], x10) |
||||
xor(out[44:], in[44:], x11) |
||||
xor(out[48:], in[48:], x12) |
||||
xor(out[52:], in[52:], x13) |
||||
xor(out[56:], in[56:], x14) |
||||
xor(out[60:], in[60:], x15) |
||||
} |
||||
// copy any trailing bytes out of the buffer and into dst
|
||||
if rem != 0 { |
||||
s.len = 64 - rem |
||||
copy(dst[fin:], s.buf[len(s.buf)-64:]) |
||||
} |
||||
} |
||||
|
||||
// Advance discards bytes in the key stream until the next 64 byte block
|
||||
// boundary is reached and updates the counter accordingly. If the key
|
||||
// stream is already at a block boundary no bytes will be discarded and
|
||||
// the counter will be unchanged.
|
||||
func (s *Cipher) Advance() { |
||||
s.len -= s.len % 64 |
||||
if s.len == 0 { |
||||
s.buf = [len(s.buf)]byte{} |
||||
} |
||||
} |
||||
|
||||
// XORKeyStream crypts bytes from in to out using the given key and counters.
|
||||
// In and out must overlap entirely or not at all. Counter contains the raw
|
||||
// ChaCha20 counter bytes (i.e. block counter followed by nonce).
|
||||
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) { |
||||
s := Cipher{ |
||||
key: [8]uint32{ |
||||
binary.LittleEndian.Uint32(key[0:4]), |
||||
binary.LittleEndian.Uint32(key[4:8]), |
||||
binary.LittleEndian.Uint32(key[8:12]), |
||||
binary.LittleEndian.Uint32(key[12:16]), |
||||
binary.LittleEndian.Uint32(key[16:20]), |
||||
binary.LittleEndian.Uint32(key[20:24]), |
||||
binary.LittleEndian.Uint32(key[24:28]), |
||||
binary.LittleEndian.Uint32(key[28:32]), |
||||
}, |
||||
nonce: [3]uint32{ |
||||
binary.LittleEndian.Uint32(counter[4:8]), |
||||
binary.LittleEndian.Uint32(counter[8:12]), |
||||
binary.LittleEndian.Uint32(counter[12:16]), |
||||
}, |
||||
counter: binary.LittleEndian.Uint32(counter[0:4]), |
||||
} |
||||
s.XORKeyStream(out, in) |
||||
} |
||||
|
||||
// HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a
|
||||
// nonce. It should only be used as part of the XChaCha20 construction.
|
||||
func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 { |
||||
x0, x1, x2, x3 := j0, j1, j2, j3 |
||||
x4, x5, x6, x7 := key[0], key[1], key[2], key[3] |
||||
x8, x9, x10, x11 := key[4], key[5], key[6], key[7] |
||||
x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3] |
||||
|
||||
for i := 0; i < 10; i++ { |
||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) |
||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) |
||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) |
||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) |
||||
|
||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) |
||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) |
||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) |
||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) |
||||
} |
||||
|
||||
var out [8]uint32 |
||||
out[0], out[1], out[2], out[3] = x0, x1, x2, x3 |
||||
out[4], out[5], out[6], out[7] = x12, x13, x14, x15 |
||||
return out |
||||
} |
@ -1,16 +0,0 @@ |
||||
// 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.
|
||||
|
||||
// +build !ppc64le,!arm64,!s390x arm64,!go1.11 gccgo appengine
|
||||
|
||||
package chacha20 |
||||
|
||||
const ( |
||||
bufSize = 64 |
||||
haveAsm = false |
||||
) |
||||
|
||||
func (*Cipher) xorKeyStreamAsm(dst, src []byte) { |
||||
panic("not implemented") |
||||
} |
@ -1,52 +0,0 @@ |
||||
// Copyright 2019 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 ppc64le,!gccgo,!appengine
|
||||
|
||||
package chacha20 |
||||
|
||||
import "encoding/binary" |
||||
|
||||
const ( |
||||
bufSize = 256 |
||||
haveAsm = true |
||||
) |
||||
|
||||
//go:noescape
|
||||
func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[8]uint32, counter *uint32) |
||||
|
||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) { |
||||
if len(src) >= bufSize { |
||||
chaCha20_ctr32_vmx(&dst[0], &src[0], len(src)-len(src)%bufSize, &c.key, &c.counter) |
||||
} |
||||
if len(src)%bufSize != 0 { |
||||
chaCha20_ctr32_vmx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter) |
||||
start := len(src) - len(src)%bufSize |
||||
ts, td, tb := src[start:], dst[start:], c.buf[:] |
||||
// Unroll loop to XOR 32 bytes per iteration.
|
||||
for i := 0; i < len(ts)-32; i += 32 { |
||||
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
|
||||
s0 := binary.LittleEndian.Uint64(ts[0:8]) |
||||
s1 := binary.LittleEndian.Uint64(ts[8:16]) |
||||
s2 := binary.LittleEndian.Uint64(ts[16:24]) |
||||
s3 := binary.LittleEndian.Uint64(ts[24:32]) |
||||
b0 := binary.LittleEndian.Uint64(tb[0:8]) |
||||
b1 := binary.LittleEndian.Uint64(tb[8:16]) |
||||
b2 := binary.LittleEndian.Uint64(tb[16:24]) |
||||
b3 := binary.LittleEndian.Uint64(tb[24:32]) |
||||
binary.LittleEndian.PutUint64(td[0:8], s0^b0) |
||||
binary.LittleEndian.PutUint64(td[8:16], s1^b1) |
||||
binary.LittleEndian.PutUint64(td[16:24], s2^b2) |
||||
binary.LittleEndian.PutUint64(td[24:32], s3^b3) |
||||
ts, td, tb = ts[32:], td[32:], tb[32:] |
||||
} |
||||
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
|
||||
for i, v := range ts { |
||||
td[i] = tb[i] ^ v |
||||
} |
||||
c.len = bufSize - (len(src) % bufSize) |
||||
|
||||
} |
||||
|
||||
} |
@ -1,29 +0,0 @@ |
||||
// 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.
|
||||
|
||||
// +build s390x,!gccgo,!appengine
|
||||
|
||||
package chacha20 |
||||
|
||||
import ( |
||||
"golang.org/x/sys/cpu" |
||||
) |
||||
|
||||
var haveAsm = cpu.S390X.HasVX |
||||
|
||||
const bufSize = 256 |
||||
|
||||
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
|
||||
// be called when the vector facility is available.
|
||||
// Implementation in asm_s390x.s.
|
||||
//go:noescape
|
||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int) |
||||
|
||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) { |
||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter, &c.buf, &c.len) |
||||
} |
||||
|
||||
// EXRL targets, DO NOT CALL!
|
||||
func mvcSrcToBuf() |
||||
func mvcBufToDst() |
@ -0,0 +1,39 @@ |
||||
// Copyright 2019 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 !go1.13
|
||||
|
||||
package poly1305 |
||||
|
||||
// Generic fallbacks for the math/bits intrinsics, copied from
|
||||
// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had
|
||||
// variable time fallbacks until Go 1.13.
|
||||
|
||||
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { |
||||
sum = x + y + carry |
||||
carryOut = ((x & y) | ((x | y) &^ sum)) >> 63 |
||||
return |
||||
} |
||||
|
||||
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { |
||||
diff = x - y - borrow |
||||
borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63 |
||||
return |
||||
} |
||||
|
||||
func bitsMul64(x, y uint64) (hi, lo uint64) { |
||||
const mask32 = 1<<32 - 1 |
||||
x0 := x & mask32 |
||||
x1 := x >> 32 |
||||
y0 := y & mask32 |
||||
y1 := y >> 32 |
||||
w0 := x0 * y0 |
||||
t := x1*y0 + w0>>32 |
||||
w1 := t & mask32 |
||||
w2 := t >> 32 |
||||
w1 += x0 * y1 |
||||
hi = x1*y1 + w2 + w1>>32 |
||||
lo = x * y |
||||
return |
||||
} |
@ -0,0 +1,21 @@ |
||||
// Copyright 2019 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 go1.13
|
||||
|
||||
package poly1305 |
||||
|
||||
import "math/bits" |
||||
|
||||
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { |
||||
return bits.Add64(x, y, carry) |
||||
} |
||||
|
||||
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { |
||||
return bits.Sub64(x, y, borrow) |
||||
} |
||||
|
||||
func bitsMul64(x, y uint64) (hi, lo uint64) { |
||||
return bits.Mul64(x, y) |
||||
} |
Loading…
Reference in new issue