mirror of https://github.com/ethereum/go-ethereum
crypto/bn256: full switchover to cloudflare's code (#16301)
* crypto/bn256: full switchover to cloudflare's code * crypto/bn256: only use cloudflare for optimized architectures * crypto/bn256: upstream fallback for non-optimized code * .travis, build: drop support for Go 1.8 (need type aliases) * crypto/bn256/cloudflare: enable curve mul lattice optimizationpull/17875/head
parent
0965761a45
commit
1203c6a237
@ -0,0 +1,138 @@ |
|||||||
|
// Copyright 2018 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// +build gofuzz
|
||||||
|
|
||||||
|
package bn256 |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"math/big" |
||||||
|
|
||||||
|
cloudflare "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" |
||||||
|
google "github.com/ethereum/go-ethereum/crypto/bn256/google" |
||||||
|
) |
||||||
|
|
||||||
|
// FuzzAdd fuzzez bn256 addition between the Google and Cloudflare libraries.
|
||||||
|
func FuzzAdd(data []byte) int { |
||||||
|
// Ensure we have enough data in the first place
|
||||||
|
if len(data) != 128 { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
// Ensure both libs can parse the first curve point
|
||||||
|
xc := new(cloudflare.G1) |
||||||
|
_, errc := xc.Unmarshal(data[:64]) |
||||||
|
|
||||||
|
xg := new(google.G1) |
||||||
|
_, errg := xg.Unmarshal(data[:64]) |
||||||
|
|
||||||
|
if (errc == nil) != (errg == nil) { |
||||||
|
panic("parse mismatch") |
||||||
|
} else if errc != nil { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
// Ensure both libs can parse the second curve point
|
||||||
|
yc := new(cloudflare.G1) |
||||||
|
_, errc = yc.Unmarshal(data[64:]) |
||||||
|
|
||||||
|
yg := new(google.G1) |
||||||
|
_, errg = yg.Unmarshal(data[64:]) |
||||||
|
|
||||||
|
if (errc == nil) != (errg == nil) { |
||||||
|
panic("parse mismatch") |
||||||
|
} else if errc != nil { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
// Add the two points and ensure they result in the same output
|
||||||
|
rc := new(cloudflare.G1) |
||||||
|
rc.Add(xc, yc) |
||||||
|
|
||||||
|
rg := new(google.G1) |
||||||
|
rg.Add(xg, yg) |
||||||
|
|
||||||
|
if !bytes.Equal(rc.Marshal(), rg.Marshal()) { |
||||||
|
panic("add mismatch") |
||||||
|
} |
||||||
|
return 0 |
||||||
|
} |
||||||
|
|
||||||
|
// FuzzMul fuzzez bn256 scalar multiplication between the Google and Cloudflare
|
||||||
|
// libraries.
|
||||||
|
func FuzzMul(data []byte) int { |
||||||
|
// Ensure we have enough data in the first place
|
||||||
|
if len(data) != 96 { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
// Ensure both libs can parse the curve point
|
||||||
|
pc := new(cloudflare.G1) |
||||||
|
_, errc := pc.Unmarshal(data[:64]) |
||||||
|
|
||||||
|
pg := new(google.G1) |
||||||
|
_, errg := pg.Unmarshal(data[:64]) |
||||||
|
|
||||||
|
if (errc == nil) != (errg == nil) { |
||||||
|
panic("parse mismatch") |
||||||
|
} else if errc != nil { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
// Add the two points and ensure they result in the same output
|
||||||
|
rc := new(cloudflare.G1) |
||||||
|
rc.ScalarMult(pc, new(big.Int).SetBytes(data[64:])) |
||||||
|
|
||||||
|
rg := new(google.G1) |
||||||
|
rg.ScalarMult(pg, new(big.Int).SetBytes(data[64:])) |
||||||
|
|
||||||
|
if !bytes.Equal(rc.Marshal(), rg.Marshal()) { |
||||||
|
panic("scalar mul mismatch") |
||||||
|
} |
||||||
|
return 0 |
||||||
|
} |
||||||
|
|
||||||
|
func FuzzPair(data []byte) int { |
||||||
|
// Ensure we have enough data in the first place
|
||||||
|
if len(data) != 192 { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
// Ensure both libs can parse the curve point
|
||||||
|
pc := new(cloudflare.G1) |
||||||
|
_, errc := pc.Unmarshal(data[:64]) |
||||||
|
|
||||||
|
pg := new(google.G1) |
||||||
|
_, errg := pg.Unmarshal(data[:64]) |
||||||
|
|
||||||
|
if (errc == nil) != (errg == nil) { |
||||||
|
panic("parse mismatch") |
||||||
|
} else if errc != nil { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
// Ensure both libs can parse the twist point
|
||||||
|
tc := new(cloudflare.G2) |
||||||
|
_, errc = tc.Unmarshal(data[64:]) |
||||||
|
|
||||||
|
tg := new(google.G2) |
||||||
|
_, errg = tg.Unmarshal(data[64:]) |
||||||
|
|
||||||
|
if (errc == nil) != (errg == nil) { |
||||||
|
panic("parse mismatch") |
||||||
|
} else if errc != nil { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
// Pair the two points and ensure thet result in the same output
|
||||||
|
if cloudflare.PairingCheck([]*cloudflare.G1{pc}, []*cloudflare.G2{tc}) != google.PairingCheck([]*google.G1{pg}, []*google.G2{tg}) { |
||||||
|
panic("pair mismatch") |
||||||
|
} |
||||||
|
return 0 |
||||||
|
} |
@ -1,32 +0,0 @@ |
|||||||
#define storeBlock(a0,a1,a2,a3, r) \ |
|
||||||
MOVQ a0, 0+r \
|
|
||||||
MOVQ a1, 8+r \
|
|
||||||
MOVQ a2, 16+r \
|
|
||||||
MOVQ a3, 24+r |
|
||||||
|
|
||||||
#define loadBlock(r, a0,a1,a2,a3) \ |
|
||||||
MOVQ 0+r, a0 \
|
|
||||||
MOVQ 8+r, a1 \
|
|
||||||
MOVQ 16+r, a2 \
|
|
||||||
MOVQ 24+r, a3 |
|
||||||
|
|
||||||
#define gfpCarry(a0,a1,a2,a3,a4, b0,b1,b2,b3,b4) \ |
|
||||||
\ // b = a-p
|
|
||||||
MOVQ a0, b0 \
|
|
||||||
MOVQ a1, b1 \
|
|
||||||
MOVQ a2, b2 \
|
|
||||||
MOVQ a3, b3 \
|
|
||||||
MOVQ a4, b4 \
|
|
||||||
\
|
|
||||||
SUBQ ·p2+0(SB), b0 \
|
|
||||||
SBBQ ·p2+8(SB), b1 \
|
|
||||||
SBBQ ·p2+16(SB), b2 \
|
|
||||||
SBBQ ·p2+24(SB), b3 \
|
|
||||||
SBBQ $0, b4 \
|
|
||||||
\
|
|
||||||
\ // if b is negative then return a
|
|
||||||
\ // else return b
|
|
||||||
CMOVQCC b0, a0 \
|
|
||||||
CMOVQCC b1, a1 \
|
|
||||||
CMOVQCC b2, a2 \
|
|
||||||
CMOVQCC b3, a3 |
|
@ -1,15 +0,0 @@ |
|||||||
// +build amd64,!appengine,!gccgo
|
|
||||||
|
|
||||||
package bn256 |
|
||||||
|
|
||||||
// go:noescape
|
|
||||||
func gfpNeg(c, a *gfP) |
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func gfpAdd(c, a, b *gfP) |
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func gfpSub(c, a, b *gfP) |
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func gfpMul(c, a, b *gfP) |
|
@ -0,0 +1,113 @@ |
|||||||
|
// +build arm64,!generic |
||||||
|
|
||||||
|
#define storeBlock(a0,a1,a2,a3, r) \ |
||||||
|
MOVD a0, 0+r \ |
||||||
|
MOVD a1, 8+r \ |
||||||
|
MOVD a2, 16+r \ |
||||||
|
MOVD a3, 24+r |
||||||
|
|
||||||
|
#define loadBlock(r, a0,a1,a2,a3) \ |
||||||
|
MOVD 0+r, a0 \ |
||||||
|
MOVD 8+r, a1 \ |
||||||
|
MOVD 16+r, a2 \ |
||||||
|
MOVD 24+r, a3 |
||||||
|
|
||||||
|
#define loadModulus(p0,p1,p2,p3) \ |
||||||
|
MOVD ·p2+0(SB), p0 \ |
||||||
|
MOVD ·p2+8(SB), p1 \ |
||||||
|
MOVD ·p2+16(SB), p2 \ |
||||||
|
MOVD ·p2+24(SB), p3 |
||||||
|
|
||||||
|
#include "mul_arm64.h" |
||||||
|
|
||||||
|
TEXT ·gfpNeg(SB),0,$0-16 |
||||||
|
MOVD a+8(FP), R0 |
||||||
|
loadBlock(0(R0), R1,R2,R3,R4) |
||||||
|
loadModulus(R5,R6,R7,R8) |
||||||
|
|
||||||
|
SUBS R1, R5, R1 |
||||||
|
SBCS R2, R6, R2 |
||||||
|
SBCS R3, R7, R3 |
||||||
|
SBCS R4, R8, R4 |
||||||
|
|
||||||
|
SUBS R5, R1, R5 |
||||||
|
SBCS R6, R2, R6 |
||||||
|
SBCS R7, R3, R7 |
||||||
|
SBCS R8, R4, R8 |
||||||
|
|
||||||
|
CSEL CS, R5, R1, R1 |
||||||
|
CSEL CS, R6, R2, R2 |
||||||
|
CSEL CS, R7, R3, R3 |
||||||
|
CSEL CS, R8, R4, R4 |
||||||
|
|
||||||
|
MOVD c+0(FP), R0 |
||||||
|
storeBlock(R1,R2,R3,R4, 0(R0)) |
||||||
|
RET |
||||||
|
|
||||||
|
TEXT ·gfpAdd(SB),0,$0-24 |
||||||
|
MOVD a+8(FP), R0 |
||||||
|
loadBlock(0(R0), R1,R2,R3,R4) |
||||||
|
MOVD b+16(FP), R0 |
||||||
|
loadBlock(0(R0), R5,R6,R7,R8) |
||||||
|
loadModulus(R9,R10,R11,R12) |
||||||
|
MOVD ZR, R0 |
||||||
|
|
||||||
|
ADDS R5, R1 |
||||||
|
ADCS R6, R2 |
||||||
|
ADCS R7, R3 |
||||||
|
ADCS R8, R4 |
||||||
|
ADCS ZR, R0 |
||||||
|
|
||||||
|
SUBS R9, R1, R5 |
||||||
|
SBCS R10, R2, R6 |
||||||
|
SBCS R11, R3, R7 |
||||||
|
SBCS R12, R4, R8 |
||||||
|
SBCS ZR, R0, R0 |
||||||
|
|
||||||
|
CSEL CS, R5, R1, R1 |
||||||
|
CSEL CS, R6, R2, R2 |
||||||
|
CSEL CS, R7, R3, R3 |
||||||
|
CSEL CS, R8, R4, R4 |
||||||
|
|
||||||
|
MOVD c+0(FP), R0 |
||||||
|
storeBlock(R1,R2,R3,R4, 0(R0)) |
||||||
|
RET |
||||||
|
|
||||||
|
TEXT ·gfpSub(SB),0,$0-24 |
||||||
|
MOVD a+8(FP), R0 |
||||||
|
loadBlock(0(R0), R1,R2,R3,R4) |
||||||
|
MOVD b+16(FP), R0 |
||||||
|
loadBlock(0(R0), R5,R6,R7,R8) |
||||||
|
loadModulus(R9,R10,R11,R12) |
||||||
|
|
||||||
|
SUBS R5, R1 |
||||||
|
SBCS R6, R2 |
||||||
|
SBCS R7, R3 |
||||||
|
SBCS R8, R4 |
||||||
|
|
||||||
|
CSEL CS, ZR, R9, R9 |
||||||
|
CSEL CS, ZR, R10, R10 |
||||||
|
CSEL CS, ZR, R11, R11 |
||||||
|
CSEL CS, ZR, R12, R12 |
||||||
|
|
||||||
|
ADDS R9, R1 |
||||||
|
ADCS R10, R2 |
||||||
|
ADCS R11, R3 |
||||||
|
ADCS R12, R4 |
||||||
|
|
||||||
|
MOVD c+0(FP), R0 |
||||||
|
storeBlock(R1,R2,R3,R4, 0(R0)) |
||||||
|
RET |
||||||
|
|
||||||
|
TEXT ·gfpMul(SB),0,$0-24 |
||||||
|
MOVD a+8(FP), R0 |
||||||
|
loadBlock(0(R0), R1,R2,R3,R4) |
||||||
|
MOVD b+16(FP), R0 |
||||||
|
loadBlock(0(R0), R5,R6,R7,R8) |
||||||
|
|
||||||
|
mul(R9,R10,R11,R12,R13,R14,R15,R16) |
||||||
|
gfpReduce() |
||||||
|
|
||||||
|
MOVD c+0(FP), R0 |
||||||
|
storeBlock(R1,R2,R3,R4, 0(R0)) |
||||||
|
RET |
@ -0,0 +1,18 @@ |
|||||||
|
// +build amd64,!generic arm64,!generic
|
||||||
|
|
||||||
|
package bn256 |
||||||
|
|
||||||
|
// This file contains forward declarations for the architecture-specific
|
||||||
|
// assembly implementations of these functions, provided that they exist.
|
||||||
|
|
||||||
|
// go:noescape
|
||||||
|
func gfpNeg(c, a *gfP) |
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
func gfpAdd(c, a, b *gfP) |
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
func gfpSub(c, a, b *gfP) |
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
func gfpMul(c, a, b *gfP) |
@ -0,0 +1,173 @@ |
|||||||
|
// +build !amd64,!arm64 generic
|
||||||
|
|
||||||
|
package bn256 |
||||||
|
|
||||||
|
func gfpCarry(a *gfP, head uint64) { |
||||||
|
b := &gfP{} |
||||||
|
|
||||||
|
var carry uint64 |
||||||
|
for i, pi := range p2 { |
||||||
|
ai := a[i] |
||||||
|
bi := ai - pi - carry |
||||||
|
b[i] = bi |
||||||
|
carry = (pi&^ai | (pi|^ai)&bi) >> 63 |
||||||
|
} |
||||||
|
carry = carry &^ head |
||||||
|
|
||||||
|
// If b is negative, then return a.
|
||||||
|
// Else return b.
|
||||||
|
carry = -carry |
||||||
|
ncarry := ^carry |
||||||
|
for i := 0; i < 4; i++ { |
||||||
|
a[i] = (a[i] & carry) | (b[i] & ncarry) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func gfpNeg(c, a *gfP) { |
||||||
|
var carry uint64 |
||||||
|
for i, pi := range p2 { |
||||||
|
ai := a[i] |
||||||
|
ci := pi - ai - carry |
||||||
|
c[i] = ci |
||||||
|
carry = (ai&^pi | (ai|^pi)&ci) >> 63 |
||||||
|
} |
||||||
|
gfpCarry(c, 0) |
||||||
|
} |
||||||
|
|
||||||
|
func gfpAdd(c, a, b *gfP) { |
||||||
|
var carry uint64 |
||||||
|
for i, ai := range a { |
||||||
|
bi := b[i] |
||||||
|
ci := ai + bi + carry |
||||||
|
c[i] = ci |
||||||
|
carry = (ai&bi | (ai|bi)&^ci) >> 63 |
||||||
|
} |
||||||
|
gfpCarry(c, carry) |
||||||
|
} |
||||||
|
|
||||||
|
func gfpSub(c, a, b *gfP) { |
||||||
|
t := &gfP{} |
||||||
|
|
||||||
|
var carry uint64 |
||||||
|
for i, pi := range p2 { |
||||||
|
bi := b[i] |
||||||
|
ti := pi - bi - carry |
||||||
|
t[i] = ti |
||||||
|
carry = (bi&^pi | (bi|^pi)&ti) >> 63 |
||||||
|
} |
||||||
|
|
||||||
|
carry = 0 |
||||||
|
for i, ai := range a { |
||||||
|
ti := t[i] |
||||||
|
ci := ai + ti + carry |
||||||
|
c[i] = ci |
||||||
|
carry = (ai&ti | (ai|ti)&^ci) >> 63 |
||||||
|
} |
||||||
|
gfpCarry(c, carry) |
||||||
|
} |
||||||
|
|
||||||
|
func mul(a, b [4]uint64) [8]uint64 { |
||||||
|
const ( |
||||||
|
mask16 uint64 = 0x0000ffff |
||||||
|
mask32 uint64 = 0xffffffff |
||||||
|
) |
||||||
|
|
||||||
|
var buff [32]uint64 |
||||||
|
for i, ai := range a { |
||||||
|
a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48 |
||||||
|
|
||||||
|
for j, bj := range b { |
||||||
|
b0, b2 := bj&mask32, bj>>32 |
||||||
|
|
||||||
|
off := 4 * (i + j) |
||||||
|
buff[off+0] += a0 * b0 |
||||||
|
buff[off+1] += a1 * b0 |
||||||
|
buff[off+2] += a2*b0 + a0*b2 |
||||||
|
buff[off+3] += a3*b0 + a1*b2 |
||||||
|
buff[off+4] += a2 * b2 |
||||||
|
buff[off+5] += a3 * b2 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for i := uint(1); i < 4; i++ { |
||||||
|
shift := 16 * i |
||||||
|
|
||||||
|
var head, carry uint64 |
||||||
|
for j := uint(0); j < 8; j++ { |
||||||
|
block := 4 * j |
||||||
|
|
||||||
|
xi := buff[block] |
||||||
|
yi := (buff[block+i] << shift) + head |
||||||
|
zi := xi + yi + carry |
||||||
|
buff[block] = zi |
||||||
|
carry = (xi&yi | (xi|yi)&^zi) >> 63 |
||||||
|
|
||||||
|
head = buff[block+i] >> (64 - shift) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return [8]uint64{buff[0], buff[4], buff[8], buff[12], buff[16], buff[20], buff[24], buff[28]} |
||||||
|
} |
||||||
|
|
||||||
|
func halfMul(a, b [4]uint64) [4]uint64 { |
||||||
|
const ( |
||||||
|
mask16 uint64 = 0x0000ffff |
||||||
|
mask32 uint64 = 0xffffffff |
||||||
|
) |
||||||
|
|
||||||
|
var buff [18]uint64 |
||||||
|
for i, ai := range a { |
||||||
|
a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48 |
||||||
|
|
||||||
|
for j, bj := range b { |
||||||
|
if i+j > 3 { |
||||||
|
break |
||||||
|
} |
||||||
|
b0, b2 := bj&mask32, bj>>32 |
||||||
|
|
||||||
|
off := 4 * (i + j) |
||||||
|
buff[off+0] += a0 * b0 |
||||||
|
buff[off+1] += a1 * b0 |
||||||
|
buff[off+2] += a2*b0 + a0*b2 |
||||||
|
buff[off+3] += a3*b0 + a1*b2 |
||||||
|
buff[off+4] += a2 * b2 |
||||||
|
buff[off+5] += a3 * b2 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for i := uint(1); i < 4; i++ { |
||||||
|
shift := 16 * i |
||||||
|
|
||||||
|
var head, carry uint64 |
||||||
|
for j := uint(0); j < 4; j++ { |
||||||
|
block := 4 * j |
||||||
|
|
||||||
|
xi := buff[block] |
||||||
|
yi := (buff[block+i] << shift) + head |
||||||
|
zi := xi + yi + carry |
||||||
|
buff[block] = zi |
||||||
|
carry = (xi&yi | (xi|yi)&^zi) >> 63 |
||||||
|
|
||||||
|
head = buff[block+i] >> (64 - shift) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return [4]uint64{buff[0], buff[4], buff[8], buff[12]} |
||||||
|
} |
||||||
|
|
||||||
|
func gfpMul(c, a, b *gfP) { |
||||||
|
T := mul(*a, *b) |
||||||
|
m := halfMul([4]uint64{T[0], T[1], T[2], T[3]}, np) |
||||||
|
t := mul([4]uint64{m[0], m[1], m[2], m[3]}, p2) |
||||||
|
|
||||||
|
var carry uint64 |
||||||
|
for i, Ti := range T { |
||||||
|
ti := t[i] |
||||||
|
zi := Ti + ti + carry |
||||||
|
T[i] = zi |
||||||
|
carry = (Ti&ti | (Ti|ti)&^zi) >> 63 |
||||||
|
} |
||||||
|
|
||||||
|
*c = gfP{T[4], T[5], T[6], T[7]} |
||||||
|
gfpCarry(c, carry) |
||||||
|
} |
@ -1,19 +0,0 @@ |
|||||||
// +build !amd64 appengine gccgo
|
|
||||||
|
|
||||||
package bn256 |
|
||||||
|
|
||||||
func gfpNeg(c, a *gfP) { |
|
||||||
panic("unsupported architecture") |
|
||||||
} |
|
||||||
|
|
||||||
func gfpAdd(c, a, b *gfP) { |
|
||||||
panic("unsupported architecture") |
|
||||||
} |
|
||||||
|
|
||||||
func gfpSub(c, a, b *gfP) { |
|
||||||
panic("unsupported architecture") |
|
||||||
} |
|
||||||
|
|
||||||
func gfpMul(c, a, b *gfP) { |
|
||||||
panic("unsupported architecture") |
|
||||||
} |
|
@ -0,0 +1,115 @@ |
|||||||
|
package bn256 |
||||||
|
|
||||||
|
import ( |
||||||
|
"math/big" |
||||||
|
) |
||||||
|
|
||||||
|
var half = new(big.Int).Rsh(Order, 1) |
||||||
|
|
||||||
|
var curveLattice = &lattice{ |
||||||
|
vectors: [][]*big.Int{ |
||||||
|
{bigFromBase10("147946756881789319000765030803803410728"), bigFromBase10("147946756881789319010696353538189108491")}, |
||||||
|
{bigFromBase10("147946756881789319020627676272574806254"), bigFromBase10("-147946756881789318990833708069417712965")}, |
||||||
|
}, |
||||||
|
inverse: []*big.Int{ |
||||||
|
bigFromBase10("147946756881789318990833708069417712965"), |
||||||
|
bigFromBase10("147946756881789319010696353538189108491"), |
||||||
|
}, |
||||||
|
det: bigFromBase10("43776485743678550444492811490514550177096728800832068687396408373151616991234"), |
||||||
|
} |
||||||
|
|
||||||
|
var targetLattice = &lattice{ |
||||||
|
vectors: [][]*big.Int{ |
||||||
|
{bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697763"), bigFromBase10("9931322734385697764")}, |
||||||
|
{bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848882"), bigFromBase10("-9931322734385697762")}, |
||||||
|
{bigFromBase10("-9931322734385697762"), bigFromBase10("-4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("-4965661367192848882")}, |
||||||
|
{bigFromBase10("9931322734385697763"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881")}, |
||||||
|
}, |
||||||
|
inverse: []*big.Int{ |
||||||
|
bigFromBase10("734653495049373973658254490726798021314063399421879442165"), |
||||||
|
bigFromBase10("147946756881789319000765030803803410728"), |
||||||
|
bigFromBase10("-147946756881789319005730692170996259609"), |
||||||
|
bigFromBase10("1469306990098747947464455738335385361643788813749140841702"), |
||||||
|
}, |
||||||
|
det: new(big.Int).Set(Order), |
||||||
|
} |
||||||
|
|
||||||
|
type lattice struct { |
||||||
|
vectors [][]*big.Int |
||||||
|
inverse []*big.Int |
||||||
|
det *big.Int |
||||||
|
} |
||||||
|
|
||||||
|
// decompose takes a scalar mod Order as input and finds a short, positive decomposition of it wrt to the lattice basis.
|
||||||
|
func (l *lattice) decompose(k *big.Int) []*big.Int { |
||||||
|
n := len(l.inverse) |
||||||
|
|
||||||
|
// Calculate closest vector in lattice to <k,0,0,...> with Babai's rounding.
|
||||||
|
c := make([]*big.Int, n) |
||||||
|
for i := 0; i < n; i++ { |
||||||
|
c[i] = new(big.Int).Mul(k, l.inverse[i]) |
||||||
|
round(c[i], l.det) |
||||||
|
} |
||||||
|
|
||||||
|
// Transform vectors according to c and subtract <k,0,0,...>.
|
||||||
|
out := make([]*big.Int, n) |
||||||
|
temp := new(big.Int) |
||||||
|
|
||||||
|
for i := 0; i < n; i++ { |
||||||
|
out[i] = new(big.Int) |
||||||
|
|
||||||
|
for j := 0; j < n; j++ { |
||||||
|
temp.Mul(c[j], l.vectors[j][i]) |
||||||
|
out[i].Add(out[i], temp) |
||||||
|
} |
||||||
|
|
||||||
|
out[i].Neg(out[i]) |
||||||
|
out[i].Add(out[i], l.vectors[0][i]).Add(out[i], l.vectors[0][i]) |
||||||
|
} |
||||||
|
out[0].Add(out[0], k) |
||||||
|
|
||||||
|
return out |
||||||
|
} |
||||||
|
|
||||||
|
func (l *lattice) Precompute(add func(i, j uint)) { |
||||||
|
n := uint(len(l.vectors)) |
||||||
|
total := uint(1) << n |
||||||
|
|
||||||
|
for i := uint(0); i < n; i++ { |
||||||
|
for j := uint(0); j < total; j++ { |
||||||
|
if (j>>i)&1 == 1 { |
||||||
|
add(i, j) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (l *lattice) Multi(scalar *big.Int) []uint8 { |
||||||
|
decomp := l.decompose(scalar) |
||||||
|
|
||||||
|
maxLen := 0 |
||||||
|
for _, x := range decomp { |
||||||
|
if x.BitLen() > maxLen { |
||||||
|
maxLen = x.BitLen() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
out := make([]uint8, maxLen) |
||||||
|
for j, x := range decomp { |
||||||
|
for i := 0; i < maxLen; i++ { |
||||||
|
out[i] += uint8(x.Bit(i)) << uint(j) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return out |
||||||
|
} |
||||||
|
|
||||||
|
// round sets num to num/denom rounded to the nearest integer.
|
||||||
|
func round(num, denom *big.Int) { |
||||||
|
r := new(big.Int) |
||||||
|
num.DivMod(num, denom, r) |
||||||
|
|
||||||
|
if r.Cmp(half) == 1 { |
||||||
|
num.Add(num, big.NewInt(1)) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package bn256 |
||||||
|
|
||||||
|
import ( |
||||||
|
"crypto/rand" |
||||||
|
|
||||||
|
"testing" |
||||||
|
) |
||||||
|
|
||||||
|
func TestLatticeReduceCurve(t *testing.T) { |
||||||
|
k, _ := rand.Int(rand.Reader, Order) |
||||||
|
ks := curveLattice.decompose(k) |
||||||
|
|
||||||
|
if ks[0].BitLen() > 130 || ks[1].BitLen() > 130 { |
||||||
|
t.Fatal("reduction too large") |
||||||
|
} else if ks[0].Sign() < 0 || ks[1].Sign() < 0 { |
||||||
|
t.Fatal("reduction must be positive") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestLatticeReduceTarget(t *testing.T) { |
||||||
|
k, _ := rand.Int(rand.Reader, Order) |
||||||
|
ks := targetLattice.decompose(k) |
||||||
|
|
||||||
|
if ks[0].BitLen() > 66 || ks[1].BitLen() > 66 || ks[2].BitLen() > 66 || ks[3].BitLen() > 66 { |
||||||
|
t.Fatal("reduction too large") |
||||||
|
} else if ks[0].Sign() < 0 || ks[1].Sign() < 0 || ks[2].Sign() < 0 || ks[3].Sign() < 0 { |
||||||
|
t.Fatal("reduction must be positive") |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,133 @@ |
|||||||
|
#define mul(c0,c1,c2,c3,c4,c5,c6,c7) \ |
||||||
|
MUL R1, R5, c0 \
|
||||||
|
UMULH R1, R5, c1 \
|
||||||
|
MUL R1, R6, R0 \
|
||||||
|
ADDS R0, c1 \
|
||||||
|
UMULH R1, R6, c2 \
|
||||||
|
MUL R1, R7, R0 \
|
||||||
|
ADCS R0, c2 \
|
||||||
|
UMULH R1, R7, c3 \
|
||||||
|
MUL R1, R8, R0 \
|
||||||
|
ADCS R0, c3 \
|
||||||
|
UMULH R1, R8, c4 \
|
||||||
|
ADCS ZR, c4 \
|
||||||
|
\
|
||||||
|
MUL R2, R5, R25 \
|
||||||
|
UMULH R2, R5, R26 \
|
||||||
|
MUL R2, R6, R0 \
|
||||||
|
ADDS R0, R26 \
|
||||||
|
UMULH R2, R6, R27 \
|
||||||
|
MUL R2, R7, R0 \
|
||||||
|
ADCS R0, R27 \
|
||||||
|
UMULH R2, R7, R29 \
|
||||||
|
MUL R2, R8, R0 \
|
||||||
|
ADCS R0, R29 \
|
||||||
|
UMULH R2, R8, c5 \
|
||||||
|
ADCS ZR, c5 \
|
||||||
|
ADDS R25, c1 \
|
||||||
|
ADCS R26, c2 \
|
||||||
|
ADCS R27, c3 \
|
||||||
|
ADCS R29, c4 \
|
||||||
|
ADCS ZR, c5 \
|
||||||
|
\
|
||||||
|
MUL R3, R5, R25 \
|
||||||
|
UMULH R3, R5, R26 \
|
||||||
|
MUL R3, R6, R0 \
|
||||||
|
ADDS R0, R26 \
|
||||||
|
UMULH R3, R6, R27 \
|
||||||
|
MUL R3, R7, R0 \
|
||||||
|
ADCS R0, R27 \
|
||||||
|
UMULH R3, R7, R29 \
|
||||||
|
MUL R3, R8, R0 \
|
||||||
|
ADCS R0, R29 \
|
||||||
|
UMULH R3, R8, c6 \
|
||||||
|
ADCS ZR, c6 \
|
||||||
|
ADDS R25, c2 \
|
||||||
|
ADCS R26, c3 \
|
||||||
|
ADCS R27, c4 \
|
||||||
|
ADCS R29, c5 \
|
||||||
|
ADCS ZR, c6 \
|
||||||
|
\
|
||||||
|
MUL R4, R5, R25 \
|
||||||
|
UMULH R4, R5, R26 \
|
||||||
|
MUL R4, R6, R0 \
|
||||||
|
ADDS R0, R26 \
|
||||||
|
UMULH R4, R6, R27 \
|
||||||
|
MUL R4, R7, R0 \
|
||||||
|
ADCS R0, R27 \
|
||||||
|
UMULH R4, R7, R29 \
|
||||||
|
MUL R4, R8, R0 \
|
||||||
|
ADCS R0, R29 \
|
||||||
|
UMULH R4, R8, c7 \
|
||||||
|
ADCS ZR, c7 \
|
||||||
|
ADDS R25, c3 \
|
||||||
|
ADCS R26, c4 \
|
||||||
|
ADCS R27, c5 \
|
||||||
|
ADCS R29, c6 \
|
||||||
|
ADCS ZR, c7 |
||||||
|
|
||||||
|
#define gfpReduce() \ |
||||||
|
\ // m = (T * N') mod R, store m in R1:R2:R3:R4
|
||||||
|
MOVD ·np+0(SB), R17 \
|
||||||
|
MOVD ·np+8(SB), R18 \
|
||||||
|
MOVD ·np+16(SB), R19 \
|
||||||
|
MOVD ·np+24(SB), R20 \
|
||||||
|
\
|
||||||
|
MUL R9, R17, R1 \
|
||||||
|
UMULH R9, R17, R2 \
|
||||||
|
MUL R9, R18, R0 \
|
||||||
|
ADDS R0, R2 \
|
||||||
|
UMULH R9, R18, R3 \
|
||||||
|
MUL R9, R19, R0 \
|
||||||
|
ADCS R0, R3 \
|
||||||
|
UMULH R9, R19, R4 \
|
||||||
|
MUL R9, R20, R0 \
|
||||||
|
ADCS R0, R4 \
|
||||||
|
\
|
||||||
|
MUL R10, R17, R21 \
|
||||||
|
UMULH R10, R17, R22 \
|
||||||
|
MUL R10, R18, R0 \
|
||||||
|
ADDS R0, R22 \
|
||||||
|
UMULH R10, R18, R23 \
|
||||||
|
MUL R10, R19, R0 \
|
||||||
|
ADCS R0, R23 \
|
||||||
|
ADDS R21, R2 \
|
||||||
|
ADCS R22, R3 \
|
||||||
|
ADCS R23, R4 \
|
||||||
|
\
|
||||||
|
MUL R11, R17, R21 \
|
||||||
|
UMULH R11, R17, R22 \
|
||||||
|
MUL R11, R18, R0 \
|
||||||
|
ADDS R0, R22 \
|
||||||
|
ADDS R21, R3 \
|
||||||
|
ADCS R22, R4 \
|
||||||
|
\
|
||||||
|
MUL R12, R17, R21 \
|
||||||
|
ADDS R21, R4 \
|
||||||
|
\
|
||||||
|
\ // m * N
|
||||||
|
loadModulus(R5,R6,R7,R8) \
|
||||||
|
mul(R17,R18,R19,R20,R21,R22,R23,R24) \
|
||||||
|
\
|
||||||
|
\ // Add the 512-bit intermediate to m*N
|
||||||
|
MOVD ZR, R25 \
|
||||||
|
ADDS R9, R17 \
|
||||||
|
ADCS R10, R18 \
|
||||||
|
ADCS R11, R19 \
|
||||||
|
ADCS R12, R20 \
|
||||||
|
ADCS R13, R21 \
|
||||||
|
ADCS R14, R22 \
|
||||||
|
ADCS R15, R23 \
|
||||||
|
ADCS R16, R24 \
|
||||||
|
ADCS ZR, R25 \
|
||||||
|
\
|
||||||
|
\ // Our output is R21:R22:R23:R24. Reduce mod p if necessary.
|
||||||
|
SUBS R5, R21, R10 \
|
||||||
|
SBCS R6, R22, R11 \
|
||||||
|
SBCS R7, R23, R12 \
|
||||||
|
SBCS R8, R24, R13 \
|
||||||
|
\
|
||||||
|
CSEL CS, R10, R21, R1 \
|
||||||
|
CSEL CS, R11, R22, R2 \
|
||||||
|
CSEL CS, R12, R23, R3 \
|
||||||
|
CSEL CS, R13, R24, R4 |
Loading…
Reference in new issue