package nistec
import (
"crypto/internal/nistec/fiat"
"crypto/subtle"
"errors"
"sync"
)
const p224ElementLength = 28
type P224Point struct {
x , y , z *fiat .P224Element
}
func NewP224Point () *P224Point {
return &P224Point {
x : new (fiat .P224Element ),
y : new (fiat .P224Element ).One (),
z : new (fiat .P224Element ),
}
}
func (p *P224Point ) SetGenerator () *P224Point {
p .x .SetBytes ([]byte {0xb7 , 0xe , 0xc , 0xbd , 0x6b , 0xb4 , 0xbf , 0x7f , 0x32 , 0x13 , 0x90 , 0xb9 , 0x4a , 0x3 , 0xc1 , 0xd3 , 0x56 , 0xc2 , 0x11 , 0x22 , 0x34 , 0x32 , 0x80 , 0xd6 , 0x11 , 0x5c , 0x1d , 0x21 })
p .y .SetBytes ([]byte {0xbd , 0x37 , 0x63 , 0x88 , 0xb5 , 0xf7 , 0x23 , 0xfb , 0x4c , 0x22 , 0xdf , 0xe6 , 0xcd , 0x43 , 0x75 , 0xa0 , 0x5a , 0x7 , 0x47 , 0x64 , 0x44 , 0xd5 , 0x81 , 0x99 , 0x85 , 0x0 , 0x7e , 0x34 })
p .z .One ()
return p
}
func (p *P224Point ) Set (q *P224Point ) *P224Point {
p .x .Set (q .x )
p .y .Set (q .y )
p .z .Set (q .z )
return p
}
func (p *P224Point ) SetBytes (b []byte ) (*P224Point , error ) {
switch {
case len (b ) == 1 && b [0 ] == 0 :
return p .Set (NewP224Point ()), nil
case len (b ) == 1 +2 *p224ElementLength && b [0 ] == 4 :
x , err := new (fiat .P224Element ).SetBytes (b [1 : 1 +p224ElementLength ])
if err != nil {
return nil , err
}
y , err := new (fiat .P224Element ).SetBytes (b [1 +p224ElementLength :])
if err != nil {
return nil , err
}
if err := p224CheckOnCurve (x , y ); err != nil {
return nil , err
}
p .x .Set (x )
p .y .Set (y )
p .z .One ()
return p , nil
case len (b ) == 1 +p224ElementLength && (b [0 ] == 2 || b [0 ] == 3 ):
x , err := new (fiat .P224Element ).SetBytes (b [1 :])
if err != nil {
return nil , err
}
y := p224Polynomial (new (fiat .P224Element ), x )
if !p224Sqrt (y , y ) {
return nil , errors .New ("invalid P224 compressed point encoding" )
}
otherRoot := new (fiat .P224Element )
otherRoot .Sub (otherRoot , y )
cond := y .Bytes ()[p224ElementLength -1 ]&1 ^ b [0 ]&1
y .Select (otherRoot , y , int (cond ))
p .x .Set (x )
p .y .Set (y )
p .z .One ()
return p , nil
default :
return nil , errors .New ("invalid P224 point encoding" )
}
}
var _p224B *fiat .P224Element
var _p224BOnce sync .Once
func p224B () *fiat .P224Element {
_p224BOnce .Do (func () {
_p224B , _ = new (fiat .P224Element ).SetBytes ([]byte {0xb4 , 0x5 , 0xa , 0x85 , 0xc , 0x4 , 0xb3 , 0xab , 0xf5 , 0x41 , 0x32 , 0x56 , 0x50 , 0x44 , 0xb0 , 0xb7 , 0xd7 , 0xbf , 0xd8 , 0xba , 0x27 , 0xb , 0x39 , 0x43 , 0x23 , 0x55 , 0xff , 0xb4 })
})
return _p224B
}
func p224Polynomial (y2 , x *fiat .P224Element ) *fiat .P224Element {
y2 .Square (x )
y2 .Mul (y2 , x )
threeX := new (fiat .P224Element ).Add (x , x )
threeX .Add (threeX , x )
y2 .Sub (y2 , threeX )
return y2 .Add (y2 , p224B ())
}
func p224CheckOnCurve (x , y *fiat .P224Element ) error {
rhs := p224Polynomial (new (fiat .P224Element ), x )
lhs := new (fiat .P224Element ).Square (y )
if rhs .Equal (lhs ) != 1 {
return errors .New ("P224 point not on curve" )
}
return nil
}
func (p *P224Point ) Bytes () []byte {
var out [1 + 2 *p224ElementLength ]byte
return p .bytes (&out )
}
func (p *P224Point ) bytes (out *[1 + 2 *p224ElementLength ]byte ) []byte {
if p .z .IsZero () == 1 {
return append (out [:0 ], 0 )
}
zinv := new (fiat .P224Element ).Invert (p .z )
x := new (fiat .P224Element ).Mul (p .x , zinv )
y := new (fiat .P224Element ).Mul (p .y , zinv )
buf := append (out [:0 ], 4 )
buf = append (buf , x .Bytes ()...)
buf = append (buf , y .Bytes ()...)
return buf
}
func (p *P224Point ) BytesX () ([]byte , error ) {
var out [p224ElementLength ]byte
return p .bytesX (&out )
}
func (p *P224Point ) bytesX (out *[p224ElementLength ]byte ) ([]byte , error ) {
if p .z .IsZero () == 1 {
return nil , errors .New ("P224 point is the point at infinity" )
}
zinv := new (fiat .P224Element ).Invert (p .z )
x := new (fiat .P224Element ).Mul (p .x , zinv )
return append (out [:0 ], x .Bytes ()...), nil
}
func (p *P224Point ) BytesCompressed () []byte {
var out [1 + p224ElementLength ]byte
return p .bytesCompressed (&out )
}
func (p *P224Point ) bytesCompressed (out *[1 + p224ElementLength ]byte ) []byte {
if p .z .IsZero () == 1 {
return append (out [:0 ], 0 )
}
zinv := new (fiat .P224Element ).Invert (p .z )
x := new (fiat .P224Element ).Mul (p .x , zinv )
y := new (fiat .P224Element ).Mul (p .y , zinv )
buf := append (out [:0 ], 2 )
buf [0 ] |= y .Bytes ()[p224ElementLength -1 ] & 1
buf = append (buf , x .Bytes ()...)
return buf
}
func (q *P224Point ) Add (p1 , p2 *P224Point ) *P224Point {
t0 := new (fiat .P224Element ).Mul (p1 .x , p2 .x )
t1 := new (fiat .P224Element ).Mul (p1 .y , p2 .y )
t2 := new (fiat .P224Element ).Mul (p1 .z , p2 .z )
t3 := new (fiat .P224Element ).Add (p1 .x , p1 .y )
t4 := new (fiat .P224Element ).Add (p2 .x , p2 .y )
t3 .Mul (t3 , t4 )
t4 .Add (t0 , t1 )
t3 .Sub (t3 , t4 )
t4 .Add (p1 .y , p1 .z )
x3 := new (fiat .P224Element ).Add (p2 .y , p2 .z )
t4 .Mul (t4 , x3 )
x3 .Add (t1 , t2 )
t4 .Sub (t4 , x3 )
x3 .Add (p1 .x , p1 .z )
y3 := new (fiat .P224Element ).Add (p2 .x , p2 .z )
x3 .Mul (x3 , y3 )
y3 .Add (t0 , t2 )
y3 .Sub (x3 , y3 )
z3 := new (fiat .P224Element ).Mul (p224B (), t2 )
x3 .Sub (y3 , z3 )
z3 .Add (x3 , x3 )
x3 .Add (x3 , z3 )
z3 .Sub (t1 , x3 )
x3 .Add (t1 , x3 )
y3 .Mul (p224B (), y3 )
t1 .Add (t2 , t2 )
t2 .Add (t1 , t2 )
y3 .Sub (y3 , t2 )
y3 .Sub (y3 , t0 )
t1 .Add (y3 , y3 )
y3 .Add (t1 , y3 )
t1 .Add (t0 , t0 )
t0 .Add (t1 , t0 )
t0 .Sub (t0 , t2 )
t1 .Mul (t4 , y3 )
t2 .Mul (t0 , y3 )
y3 .Mul (x3 , z3 )
y3 .Add (y3 , t2 )
x3 .Mul (t3 , x3 )
x3 .Sub (x3 , t1 )
z3 .Mul (t4 , z3 )
t1 .Mul (t3 , t0 )
z3 .Add (z3 , t1 )
q .x .Set (x3 )
q .y .Set (y3 )
q .z .Set (z3 )
return q
}
func (q *P224Point ) Double (p *P224Point ) *P224Point {
t0 := new (fiat .P224Element ).Square (p .x )
t1 := new (fiat .P224Element ).Square (p .y )
t2 := new (fiat .P224Element ).Square (p .z )
t3 := new (fiat .P224Element ).Mul (p .x , p .y )
t3 .Add (t3 , t3 )
z3 := new (fiat .P224Element ).Mul (p .x , p .z )
z3 .Add (z3 , z3 )
y3 := new (fiat .P224Element ).Mul (p224B (), t2 )
y3 .Sub (y3 , z3 )
x3 := new (fiat .P224Element ).Add (y3 , y3 )
y3 .Add (x3 , y3 )
x3 .Sub (t1 , y3 )
y3 .Add (t1 , y3 )
y3 .Mul (x3 , y3 )
x3 .Mul (x3 , t3 )
t3 .Add (t2 , t2 )
t2 .Add (t2 , t3 )
z3 .Mul (p224B (), z3 )
z3 .Sub (z3 , t2 )
z3 .Sub (z3 , t0 )
t3 .Add (z3 , z3 )
z3 .Add (z3 , t3 )
t3 .Add (t0 , t0 )
t0 .Add (t3 , t0 )
t0 .Sub (t0 , t2 )
t0 .Mul (t0 , z3 )
y3 .Add (y3 , t0 )
t0 .Mul (p .y , p .z )
t0 .Add (t0 , t0 )
z3 .Mul (t0 , z3 )
x3 .Sub (x3 , z3 )
z3 .Mul (t0 , t1 )
z3 .Add (z3 , z3 )
z3 .Add (z3 , z3 )
q .x .Set (x3 )
q .y .Set (y3 )
q .z .Set (z3 )
return q
}
func (q *P224Point ) Select (p1 , p2 *P224Point , cond int ) *P224Point {
q .x .Select (p1 .x , p2 .x , cond )
q .y .Select (p1 .y , p2 .y , cond )
q .z .Select (p1 .z , p2 .z , cond )
return q
}
type p224Table [15 ]*P224Point
func (table *p224Table ) Select (p *P224Point , n uint8 ) {
if n >= 16 {
panic ("nistec: internal error: p224Table called with out-of-bounds value" )
}
p .Set (NewP224Point ())
for i := uint8 (1 ); i < 16 ; i ++ {
cond := subtle .ConstantTimeByteEq (i , n )
p .Select (table [i -1 ], p , cond )
}
}
func (p *P224Point ) ScalarMult (q *P224Point , scalar []byte ) (*P224Point , error ) {
var table = p224Table {NewP224Point (), NewP224Point (), NewP224Point (),
NewP224Point (), NewP224Point (), NewP224Point (), NewP224Point (),
NewP224Point (), NewP224Point (), NewP224Point (), NewP224Point (),
NewP224Point (), NewP224Point (), NewP224Point (), NewP224Point ()}
table [0 ].Set (q )
for i := 1 ; i < 15 ; i += 2 {
table [i ].Double (table [i /2 ])
table [i +1 ].Add (table [i ], q )
}
t := NewP224Point ()
p .Set (NewP224Point ())
for i , byte := range scalar {
if i != 0 {
p .Double (p )
p .Double (p )
p .Double (p )
p .Double (p )
}
windowValue := byte >> 4
table .Select (t , windowValue )
p .Add (p , t )
p .Double (p )
p .Double (p )
p .Double (p )
p .Double (p )
windowValue = byte & 0b1111
table .Select (t , windowValue )
p .Add (p , t )
}
return p , nil
}
var p224GeneratorTable *[p224ElementLength * 2 ]p224Table
var p224GeneratorTableOnce sync .Once
func (p *P224Point ) generatorTable () *[p224ElementLength * 2 ]p224Table {
p224GeneratorTableOnce .Do (func () {
p224GeneratorTable = new ([p224ElementLength * 2 ]p224Table )
base := NewP224Point ().SetGenerator ()
for i := 0 ; i < p224ElementLength *2 ; i ++ {
p224GeneratorTable [i ][0 ] = NewP224Point ().Set (base )
for j := 1 ; j < 15 ; j ++ {
p224GeneratorTable [i ][j ] = NewP224Point ().Add (p224GeneratorTable [i ][j -1 ], base )
}
base .Double (base )
base .Double (base )
base .Double (base )
base .Double (base )
}
})
return p224GeneratorTable
}
func (p *P224Point ) ScalarBaseMult (scalar []byte ) (*P224Point , error ) {
if len (scalar ) != p224ElementLength {
return nil , errors .New ("invalid scalar length" )
}
tables := p .generatorTable ()
t := NewP224Point ()
p .Set (NewP224Point ())
tableIndex := len (tables ) - 1
for _ , byte := range scalar {
windowValue := byte >> 4
tables [tableIndex ].Select (t , windowValue )
p .Add (p , t )
tableIndex --
windowValue = byte & 0b1111
tables [tableIndex ].Select (t , windowValue )
p .Add (p , t )
tableIndex --
}
return p , nil
}
func p224Sqrt (e , x *fiat .P224Element ) (isSquare bool ) {
candidate := new (fiat .P224Element )
p224SqrtCandidate (candidate , x )
square := new (fiat .P224Element ).Square (candidate )
if square .Equal (x ) != 1 {
return false
}
e .Set (candidate )
return true
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .