Merge branch 'develop' into jsonrpc

This commit is contained in:
obscuren 2015-01-23 14:29:01 +01:00
commit 7a894e3738
85 changed files with 7796 additions and 453 deletions

View File

@ -46,7 +46,7 @@ Go Ethereum comes with several binaries found in
* `mist` Official Ethereum Browser * `mist` Official Ethereum Browser
* `ethereum` Ethereum CLI * `ethereum` Ethereum CLI
* `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suit: * `ethtest` test tool which runs with the [tests](https://github.com/ethereum/testes) suit:
`ethtest "`cat myfile.json`"`. `cat file | ethtest`.
* `evm` is a generic Ethereum Virtual Machine: `evm -code 60ff60ff -gas * `evm` is a generic Ethereum Virtual Machine: `evm -code 60ff60ff -gas
10000 -price 0 -dump`. See `-h` for a detailed description. 10000 -price 0 -dump`. See `-h` for a detailed description.

View File

@ -9,15 +9,16 @@ import Ethereum 1.0
Rectangle { Rectangle {
id: window id: window
objectName: "browserView"
anchors.fill: parent anchors.fill: parent
color: "#00000000" color: "#00000000"
property var title: "Browser" property var title: "DApps"
property var iconSource: "../browser.png" property var iconSource: "../browser.png"
property var menuItem property var menuItem
property var hideUrl: true
property alias url: webview.url property alias url: webview.url
property alias windowTitle: webview.title
property alias webView: webview property alias webView: webview
property var cleanPath: false property var cleanPath: false
@ -66,8 +67,7 @@ Rectangle {
webview.url = "http://etherian.io" webview.url = "http://etherian.io"
} }
signal messages(var messages, int id); function messages(messages, id) {
onMessages: {
// Bit of a cheat to get proper JSON // Bit of a cheat to get proper JSON
var m = JSON.parse(JSON.parse(JSON.stringify(messages))) var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
webview.postEvent("eth_changed", id, m); webview.postEvent("eth_changed", id, m);
@ -152,29 +152,32 @@ Rectangle {
color: "#CCCCCC" color: "#CCCCCC"
} }
WebView { ScrollView {
objectName: "webView"
id: webview
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right
bottom: parent.bottom bottom: parent.bottom
top: divider.bottom top: divider.bottom
} }
WebView {
function injectJs(js) { objectName: "webView"
webview.experimental.navigatorQtObjectEnabled = true; id: webview
webview.experimental.evaluateJavaScript(js) anchors.fill: parent
webview.experimental.javascriptEnabled = true;
}
function sendMessage(data) { function sendMessage(data) {
webview.experimental.postMessage(JSON.stringify(data)) webview.experimental.postMessage(JSON.stringify(data))
} }
experimental.preferences.javascriptEnabled: true experimental.preferences.javascriptEnabled: true
experimental.preferences.webAudioEnabled: true
experimental.preferences.pluginsEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
experimental.preferences.developerExtrasEnabled: true
experimental.preferences.webGLEnabled: true experimental.preferences.webGLEnabled: true
experimental.preferences.notificationsEnabled: true
experimental.preferences.localStorageEnabled: true
experimental.userAgent:"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Mist/0.1 Safari/537.36"
experimental.itemSelector: MouseArea { experimental.itemSelector: MouseArea {
// To avoid conflicting with ListView.model when inside Initiator context. // To avoid conflicting with ListView.model when inside Initiator context.
property QtObject selectorModel: model property QtObject selectorModel: model
@ -202,13 +205,9 @@ Rectangle {
itemSelector.popup() itemSelector.popup()
} }
} }
experimental.preferences.webAudioEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
experimental.preferences.developerExtrasEnabled: true
experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"] experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"]
experimental.onMessageReceived: { experimental.onMessageReceived: {
console.log("[onMessageReceived]: ", message.data) //console.log("[onMessageReceived]: ", message.data)
// TODO move to messaging.js
var data = JSON.parse(message.data) var data = JSON.parse(message.data)
try { try {
@ -338,13 +337,13 @@ Rectangle {
case "eth_newFilterString": case "eth_newFilterString":
require(1) require(1)
var id = eth.newFilterString(data.args[0]) var id = eth.newFilterString(data.args[0], window)
postData(data._id, id); postData(data._id, id);
break; break;
case "eth_newFilter": case "eth_newFilter":
require(1) require(1)
var id = eth.newFilter(data.args[0]) var id = eth.newFilter(data.args[0], window)
postData(data._id, id); postData(data._id, id);
break; break;
@ -413,11 +412,9 @@ Rectangle {
} }
} }
function post(seed, data) { function post(seed, data) {
postData(data._id, data) postData(data._id, data)
} }
function require(args, num) { function require(args, num) {
if(args.length < num) { if(args.length < num) {
throw("required argument count of "+num+" got "+args.length); throw("required argument count of "+num+" got "+args.length);
@ -429,12 +426,10 @@ Rectangle {
function postEvent(event, id, data) { function postEvent(event, id, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event})) webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
} }
function onWatchedCb(data, id) { function onWatchedCb(data, id) {
var messages = JSON.parse(data) var messages = JSON.parse(data)
postEvent("watched:"+id, messages) postEvent("watched:"+id, messages)
} }
function onNewBlockCb(block) { function onNewBlockCb(block) {
postEvent("block:new", block) postEvent("block:new", block)
} }
@ -446,7 +441,7 @@ Rectangle {
postEvent(ev, [storageObject.address, storageObject.value]) postEvent(ev, [storageObject.address, storageObject.value])
} }
} }
}
Rectangle { Rectangle {
id: sizeGrip id: sizeGrip

View File

@ -13,7 +13,6 @@ ApplicationWindow {
id: root id: root
property var ethx : Eth.ethx property var ethx : Eth.ethx
property var browser
width: 1200 width: 1200
height: 820 height: 820
@ -21,6 +20,7 @@ ApplicationWindow {
title: "Mist" title: "Mist"
/*
// This signal is used by the filter API. The filter API connects using this signal handler from // This signal is used by the filter API. The filter API connects using this signal handler from
// the different QML files and plugins. // the different QML files and plugins.
signal messages(var messages, int id); signal messages(var messages, int id);
@ -30,6 +30,7 @@ ApplicationWindow {
messages(data, receiverSeed); messages(data, receiverSeed);
root.browser.view.messages(data, receiverSeed); root.browser.view.messages(data, receiverSeed);
} }
*/
TextField { TextField {
id: copyElementHax id: copyElementHax
@ -45,8 +46,6 @@ ApplicationWindow {
// Takes care of loading all default plugins // Takes care of loading all default plugins
Component.onCompleted: { Component.onCompleted: {
var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true}); var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
var browser = addPlugin("./browser.qml", {noAdd: true, close: false, section: "ethereum", active: true});
root.browser = browser;
addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true}); addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true});
addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
@ -55,17 +54,17 @@ ApplicationWindow {
addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"});
addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"}); addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"});
addPlugin("./views/jeffcoin/jeffcoin.qml", {noAdd: true, close: false, section: "apps"})
mainSplit.setView(wallet.view, wallet.menuItem); mainSplit.setView(wallet.view, wallet.menuItem);
newBrowserTab("http://etherian.io");
// Command setup // Command setup
gui.sendCommand(0) gui.sendCommand(0)
} }
function activeView(view, menuItem) { function activeView(view, menuItem) {
mainSplit.setView(view, menuItem) mainSplit.setView(view, menuItem)
if (view.objectName === "browserView") { if (view.hideUrl) {
urlPane.visible = false; urlPane.visible = false;
mainView.anchors.top = rootView.top mainView.anchors.top = rootView.top
} else { } else {
@ -119,6 +118,13 @@ ApplicationWindow {
} }
} }
function newBrowserTab(url) {
var window = addPlugin("./browser.qml", {noAdd: true, close: true, section: "apps", active: true});
window.view.url = url;
window.menuItem.title = "Browser Tab";
activeView(window.view, window.menuItem);
}
menuBar: MenuBar { menuBar: MenuBar {
Menu { Menu {
title: "File" title: "File"
@ -130,13 +136,6 @@ ApplicationWindow {
} }
} }
/*
MenuItem {
text: "Browser"
onTriggered: eth.openBrowser()
}
*/
MenuItem { MenuItem {
text: "Add plugin" text: "Add plugin"
onTriggered: { onTriggered: {
@ -146,6 +145,14 @@ ApplicationWindow {
} }
} }
MenuItem {
text: "New tab"
shortcut: "Ctrl+t"
onTriggered: {
newBrowserTab("http://etherian.io");
}
}
MenuSeparator {} MenuSeparator {}
MenuItem { MenuItem {
@ -205,21 +212,6 @@ ApplicationWindow {
} }
MenuSeparator {} MenuSeparator {}
/*
MenuItem {
id: miningSpeed
text: "Mining: Turbo"
onTriggered: {
gui.toggleTurboMining()
if(text == "Mining: Turbo") {
text = "Mining: Normal";
} else {
text = "Mining: Turbo";
}
}
}
*/
} }
Menu { Menu {
@ -350,9 +342,6 @@ ApplicationWindow {
views[i].menuItem.setSelection(false) views[i].menuItem.setSelection(false)
} }
view.visible = true view.visible = true
//menu.border.color = "#CCCCCC"
//menu.color = "#FFFFFFFF"
menu.setSelection(true) menu.setSelection(true)
} }
@ -512,7 +501,15 @@ ApplicationWindow {
this.view.destroy() this.view.destroy()
this.destroy() this.destroy()
for (var i = 0; i < mainSplit.views.length; i++) {
var view = mainSplit.views[i];
if (view.menuItem === this) {
mainSplit.views.splice(i, 1);
break;
}
}
gui.removePlugin(this.path) gui.removePlugin(this.path)
activeView(mainSplit.views[0].view, mainSplit.views[0].menuItem);
} }
} }
} }
@ -576,7 +573,7 @@ ApplicationWindow {
Text { Text {
text: "APPS" text: "NET"
font.bold: true font.bold: true
anchors { anchors {
left: parent.left left: parent.left
@ -653,7 +650,7 @@ ApplicationWindow {
Keys.onReturnPressed: { Keys.onReturnPressed: {
if(/^https?/.test(this.text)) { if(/^https?/.test(this.text)) {
activeView(root.browser.view, root.browser.menuItem); newBrowserTab(this.text);
} else { } else {
addPlugin(this.text, {close: true, section: "apps"}) addPlugin(this.text, {close: true, section: "apps"})
} }

View File

@ -18,7 +18,6 @@ Rectangle {
property var identity: "" property var identity: ""
Component.onCompleted: { Component.onCompleted: {
identity = shh.newIdentity() identity = shh.newIdentity()
console.log("New identity:", identity)
var t = shh.watch({}, root) var t = shh.watch({}, root)
} }

View File

@ -312,23 +312,19 @@ func (self *UiLib) ToAscii(data string) string {
} }
/// Ethereum filter methods /// Ethereum filter methods
func (self *UiLib) NewFilter(object map[string]interface{}) (id int) { func (self *UiLib) NewFilter(object map[string]interface{}, view *qml.Common) (id int) {
filter := qt.NewFilterFromMap(object, self.eth) filter := qt.NewFilterFromMap(object, self.eth)
filter.MessageCallback = func(messages state.Messages) { filter.MessageCallback = func(messages state.Messages) {
self.win.Root().Call("invokeFilterCallback", xeth.ToJSMessages(messages), id) view.Call("messages", xeth.ToJSMessages(messages), id)
} }
id = self.filterManager.InstallFilter(filter) id = self.filterManager.InstallFilter(filter)
return id return id
} }
func (self *UiLib) NewFilterString(typ string) (id int) { func (self *UiLib) NewFilterString(typ string, view *qml.Common) (id int) {
filter := core.NewFilter(self.eth) filter := core.NewFilter(self.eth)
filter.BlockCallback = func(block *types.Block) { filter.BlockCallback = func(block *types.Block) {
if self.win != nil && self.win.Root() != nil { view.Call("messages", "{}", id)
self.win.Root().Call("invokeFilterCallback", "{}", id)
} else {
fmt.Println("QML is lagging")
}
} }
id = self.filterManager.InstallFilter(filter) id = self.filterManager.InstallFilter(filter)
return id return id

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"sync" "sync"
"time"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -251,15 +252,12 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Header().Time, sm.bc.CurrentBlock().Header().Time) return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Header().Time, sm.bc.CurrentBlock().Header().Time)
} }
/* XXX if block.Time() > time.Now().Unix() {
// New blocks must be within the 15 minute range of the last block. return fmt.Errorf("block time is in the future")
if diff > int64(15*time.Minute) {
return ValidationError("Block is too far in the future of last block (> 15 minutes)")
} }
*/
// Verify the nonce of the block. Return an error if it's not valid // Verify the nonce of the block. Return an error if it's not valid
if !sm.Pow.Verify(block /*block.HashNoNonce(), block.Difficulty, block.Nonce*/) { if !sm.Pow.Verify(block) {
return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Header().Nonce)) return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Header().Nonce))
} }
@ -287,21 +285,6 @@ func (sm *BlockProcessor) AccumelateRewards(statedb *state.StateDB, block, paren
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
} }
/*
uncleParent := sm.bc.GetBlock(uncle.ParentHash)
if uncleParent == nil {
return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
}
if uncleParent.Number().Cmp(new(big.Int).Sub(parent.Number(), big.NewInt(6))) < 0 {
return UncleError("Uncle too old")
}
if knownUncles.Has(string(uncle.Hash())) {
return UncleError("Uncle in chain")
}
*/
r := new(big.Int) r := new(big.Int)
r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))

View File

@ -7,9 +7,9 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/obscuren/secp256k1-go"
) )
func IsContractAddr(addr []byte) bool { func IsContractAddr(addr []byte) bool {

View File

@ -1,16 +1,25 @@
package crypto package crypto
import ( import (
"crypto/aes"
"crypto/cipher"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"fmt"
"encoding/hex"
"encoding/json"
"errors"
"code.google.com/p/go-uuid/uuid"
"code.google.com/p/go.crypto/pbkdf2"
"code.google.com/p/go.crypto/ripemd160" "code.google.com/p/go.crypto/ripemd160"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/obscuren/ecies" "github.com/obscuren/ecies"
"github.com/obscuren/secp256k1-go"
"github.com/obscuren/sha3"
) )
func init() { func init() {
@ -101,7 +110,11 @@ func SigToPub(hash, sig []byte) *ecdsa.PublicKey {
} }
func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
sig, err = secp256k1.Sign(hash, prv.D.Bytes()) if len(hash) != 32 {
return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
}
sig, err = secp256k1.Sign(hash, ethutil.LeftPadBytes(prv.D.Bytes(), prv.Params().BitSize/8))
return return
} }
@ -113,3 +126,100 @@ func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) {
key := ecies.ImportECDSA(prv) key := ecies.ImportECDSA(prv)
return key.Decrypt(rand.Reader, ct, nil, nil) return key.Decrypt(rand.Reader, ct, nil, nil)
} }
// creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
func ImportPreSaleKey(keyStore KeyStore2, keyJSON []byte, password string) (*Key, error) {
key, err := decryptPreSaleKey(keyJSON, password)
if err != nil {
return nil, err
}
id := uuid.NewRandom()
key.Id = &id
err = keyStore.StoreKey(key, password)
return key, err
}
func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) {
preSaleKeyStruct := struct {
EncSeed string
EthAddr string
Email string
BtcAddr string
}{}
err = json.Unmarshal(fileContent, &preSaleKeyStruct)
if err != nil {
return nil, err
}
encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
iv := encSeedBytes[:16]
cipherText := encSeedBytes[16:]
/*
See https://github.com/ethereum/pyethsaletool
pyethsaletool generates the encryption key from password by
2000 rounds of PBKDF2 with HMAC-SHA-256 using password as salt (:().
16 byte key length within PBKDF2 and resulting key is used as AES key
*/
passBytes := []byte(password)
derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
ethPriv := Sha3(plainText)
ecKey := ToECDSA(ethPriv)
key = &Key{
Id: nil,
PrivateKey: ecKey,
}
derivedAddr := ethutil.Bytes2Hex(key.Address())
expectedAddr := preSaleKeyStruct.EthAddr
if derivedAddr != expectedAddr {
err = errors.New("decrypted addr not equal to expected addr")
}
return key, err
}
func aesCBCDecrypt(key []byte, cipherText []byte, iv []byte) (plainText []byte, err error) {
aesBlock, err := aes.NewCipher(key)
if err != nil {
return plainText, err
}
decrypter := cipher.NewCBCDecrypter(aesBlock, iv)
paddedPlainText := make([]byte, len(cipherText))
decrypter.CryptBlocks(paddedPlainText, cipherText)
plainText = PKCS7Unpad(paddedPlainText)
if plainText == nil {
err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
}
return plainText, err
}
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
func PKCS7Pad(in []byte) []byte {
padding := 16 - (len(in) % 16)
if padding == 0 {
padding = 16
}
for i := 0; i < padding; i++ {
in = append(in, byte(padding))
}
return in
}
func PKCS7Unpad(in []byte) []byte {
if len(in) == 0 {
return nil
}
padding := in[len(in)-1]
if int(padding) > len(in) || padding > aes.BlockSize {
return nil
} else if padding == 0 {
return nil
}
for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
if in[i] != padding {
return nil
}
}
return in[:len(in)-int(padding)]
}

View File

@ -7,8 +7,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/obscuren/secp256k1-go"
) )
// These tests are sanity checks. // These tests are sanity checks.
@ -52,7 +52,7 @@ func BenchmarkSha3(b *testing.B) {
} }
func Test0Key(t *testing.T) { func Test0Key(t *testing.T) {
t.Skip()
key := ethutil.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111") key := ethutil.Hex2Bytes("1111111111111111111111111111111111111111111111111111111111111111")
p, err := secp256k1.GeneratePubKey(key) p, err := secp256k1.GeneratePubKey(key)
@ -60,3 +60,15 @@ func Test0Key(t *testing.T) {
fmt.Printf("%x\n", p) fmt.Printf("%x\n", p)
fmt.Printf("%v %x\n", err, addr) fmt.Printf("%v %x\n", err, addr)
} }
func TestInvalidSign(t *testing.T) {
_, err := Sign(make([]byte, 1), nil)
if err == nil {
t.Errorf("expected sign with hash 1 byte to error")
}
_, err = Sign(make([]byte, 33), nil)
if err == nil {
t.Errorf("expected sign with hash 33 byte to error")
}
}

View File

@ -57,7 +57,7 @@ type encryptedKeyJSON struct {
func (k *Key) Address() []byte { func (k *Key) Address() []byte {
pubBytes := FromECDSAPub(&k.PrivateKey.PublicKey) pubBytes := FromECDSAPub(&k.PrivateKey.PublicKey)
return Sha3(pubBytes)[12:] return Sha3(pubBytes[1:])[12:]
} }
func (k *Key) MarshalJSON() (j []byte, err error) { func (k *Key) MarshalJSON() (j []byte, err error) {
@ -99,9 +99,10 @@ func NewKey(rand io.Reader) *Key {
privateKeyMarshalled := elliptic.Marshal(S256(), x, y) privateKeyMarshalled := elliptic.Marshal(S256(), x, y)
privateKeyECDSA := ToECDSA(privateKeyMarshalled) privateKeyECDSA := ToECDSA(privateKeyMarshalled)
key := new(Key)
id := uuid.NewRandom() id := uuid.NewRandom()
key.Id = &id key := &Key{
key.PrivateKey = privateKeyECDSA Id: &id,
PrivateKey: privateKeyECDSA,
}
return key return key
} }

View File

@ -178,22 +178,10 @@ func DecryptKey(ks keyStorePassphrase, keyId *uuid.UUID, auth string) (keyBytes
if err != nil { if err != nil {
return nil, err return nil, err
} }
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
AES256Block, err := aes.NewCipher(derivedKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
AES256CBCDecrypter := cipher.NewCBCDecrypter(AES256Block, iv)
paddedPlainText := make([]byte, len(cipherText))
AES256CBCDecrypter.CryptBlocks(paddedPlainText, cipherText)
plainText := PKCS7Unpad(paddedPlainText)
if plainText == nil {
err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
return nil, err
}
keyBytes = plainText[:len(plainText)-32] keyBytes = plainText[:len(plainText)-32]
keyBytesHash := plainText[len(plainText)-32:] keyBytesHash := plainText[len(plainText)-32:]
if !bytes.Equal(Sha3(keyBytes), keyBytesHash) { if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
@ -211,35 +199,3 @@ func getEntropyCSPRNG(n int) []byte {
} }
return mainBuff return mainBuff
} }
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
func PKCS7Pad(in []byte) []byte {
padding := 16 - (len(in) % 16)
if padding == 0 {
padding = 16
}
for i := 0; i < padding; i++ {
in = append(in, byte(padding))
}
return in
}
func PKCS7Unpad(in []byte) []byte {
if len(in) == 0 {
return nil
}
padding := in[len(in)-1]
if int(padding) > len(in) || padding > aes.BlockSize {
return nil
} else if padding == 0 {
return nil
}
for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
if in[i] != padding {
return nil
}
}
return in[:len(in)-int(padding)]
}

View File

@ -83,3 +83,16 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestImportPreSaleKey(t *testing.T) {
// file content of a presale key file generated with:
// python pyethsaletool.py genwallet
// with password "foo"
fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
ks := NewKeyStorePassphrase(DefaultDataDir())
pass := "foo"
_, err := ImportPreSaleKey(ks, []byte(fileContent), pass)
if err != nil {
t.Fatal(err)
}
}

View File

@ -3,8 +3,8 @@ package crypto
import ( import (
"strings" "strings"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/obscuren/secp256k1-go"
) )
type KeyPair struct { type KeyPair struct {

24
crypto/secp256k1/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*~

View File

@ -0,0 +1,22 @@
secp256k1-go
=======
golang secp256k1 library
Implements cryptographic operations for the secp256k1 ECDSA curve used by Bitcoin.
Installing
===
```
sudo apt-get install gmp-dev
```
Now compiles with cgo!
Test
===
To run tests do
```
go tests
```

192
crypto/secp256k1/notes.go Normal file
View File

@ -0,0 +1,192 @@
package secp256k1
/*
<HaltingState> sipa, int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed);
<HaltingState> is that how i generate private/public keys?
<sipa> HaltingState: you pass in a random 32-byte string as seckey
<sipa> HaltingState: if it is valid, the corresponding pubkey is put in pubkey
<sipa> and true is returned
<sipa> otherwise, false is returned
<sipa> around 1 in 2^128 32-byte strings are invalid, so the odds of even ever seeing one is extremely rare
<sipa> private keys are mathematically numbers
<sipa> each has a corresponding point on the curve as public key
<sipa> a private key is just a number
<sipa> a public key is a point with x/y coordinates
<sipa> almost every 256-bit number is a valid private key (one with a point on the curve corresponding to it)
<sipa> HaltingState: ok?
<sipa> more than half of random points are not on the curve
<sipa> and actually, it is less than the square root, not less than half, sorry :)
!!!
<sipa> a private key is a NUMBER
<sipa> a public key is a POINT
<gmaxwell> half the x,y values in the field are not on the curve, a private key is an integer.
<sipa> HaltingState: yes, n,q = private keys; N,Q = corresponding public keys (N=n*G, Q=q*G); then it follows that n*Q = n*q*G = q*n*G = q*N
<sipa> that's the reason ECDH works
<sipa> multiplication is associative and commutativ
*/
/*
<HaltingState> sipa, ok; i am doing compact signatures and I want to know; can someone change the signature to get another valid signature for same message without the private key
<HaltingState> because i know they can do that for the normal 72 byte signatures that openssl was putting out
<sipa> HaltingState: if you don't enforce non-malleability, yes
<sipa> HaltingState: if you force the highest bit of t
<sipa> it _creates_ signatures that already satisfy that condition
<sipa> but it will accept ones that don't
<sipa> maybe i should change that, and be strict
<HaltingState> yes; i want some way to know signature is valid but fails malleability
<sipa> well if the highest bit of S is 1, you can take its complement
<sipa> and end up with a valid signature
<sipa> that is canonical
*/
/*
<HaltingState> sipa, I am signing messages and highest bit of the compact signature is 1!!!
<HaltingState> if (b & 0x80) == 0x80 {
<HaltingState> log.Panic("b= %v b2= %v \n", b, b&0x80)
<HaltingState> }
<sipa> what bit?
* Pengoo has quit (Ping timeout: 272 seconds)
<HaltingState> the highest bit of the first byte of signature
<sipa> it's the highest bit of S
<sipa> so the 32nd byte
<HaltingState> wtf
*/
/*
For instance, nonces are used in HTTP digest access authentication to calculate an MD5 digest
of the password. The nonces are different each time the 401 authentication challenge
response code is presented, thus making replay attacks virtually impossible.
can verify client/server match without sending password over network
*/
/*
<hanihani> one thing I dont get about armory for instance,
is how the hot-wallet can generate new addresses without
knowing the master key
*/
/*
<HaltingState> i am yelling at the telehash people for using secp256r1
instead of secp256k1; they thing r1 is "more secure" despite fact that
there is no implementation that works and wrapping it is now taking
up massive time, lol
<gmaxwell> ...
<gmaxwell> You know that the *r curves are selected via an undisclosed
secret process, right?
<gmaxwell> HaltingState: telehash is offtopic for this channel.
*/
/*
For instance, nonces are used in HTTP digest access authentication to calculate an MD5 digest
of the password. The nonces are different each time the 401 authentication challenge
response code is presented, thus making replay attacks virtually impossible.
can verify client/server match without sending password over network
*/
/*
void secp256k1_start(void);
void secp256k1_stop(void);
* Verify an ECDSA signature.
* Returns: 1: correct signature
* 0: incorrect signature
* -1: invalid public key
* -2: invalid signature
*
int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen,
const unsigned char *sig, int siglen,
const unsigned char *pubkey, int pubkeylen);
http://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.html
Why did this work? ECDSA requires a random number for each signature. If this random
number is ever used twice with the same private key it can be recovered.
This transaction was generated by a hardware bitcoin wallet using a pseudo-random number
generator that was returning the same random number every time.
Nonce is 32 bytes?
* Create an ECDSA signature.
* Returns: 1: signature created
* 0: nonce invalid, try another one
* In: msg: the message being signed
* msglen: the length of the message being signed
* seckey: pointer to a 32-byte secret key (assumed to be valid)
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
* Out: sig: pointer to a 72-byte array where the signature will be placed.
* siglen: pointer to an int, which will be updated to the signature length (<=72).
*
int secp256k1_ecdsa_sign(const unsigned char *msg, int msglen,
unsigned char *sig, int *siglen,
const unsigned char *seckey,
const unsigned char *nonce);
* Create a compact ECDSA signature (64 byte + recovery id).
* Returns: 1: signature created
* 0: nonce invalid, try another one
* In: msg: the message being signed
* msglen: the length of the message being signed
* seckey: pointer to a 32-byte secret key (assumed to be valid)
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
* Out: sig: pointer to a 64-byte array where the signature will be placed.
* recid: pointer to an int, which will be updated to contain the recovery id.
*
int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen,
unsigned char *sig64,
const unsigned char *seckey,
const unsigned char *nonce,
int *recid);
* Recover an ECDSA public key from a compact signature.
* Returns: 1: public key succesfully recovered (which guarantees a correct signature).
* 0: otherwise.
* In: msg: the message assumed to be signed
* msglen: the length of the message
* compressed: whether to recover a compressed or uncompressed pubkey
* recid: the recovery id (as returned by ecdsa_sign_compact)
* Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey.
* pubkeylen: pointer to an int that will contain the pubkey length.
*
recovery id is between 0 and 3
int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen,
const unsigned char *sig64,
unsigned char *pubkey, int *pubkeylen,
int compressed, int recid);
* Verify an ECDSA secret key.
* Returns: 1: secret key is valid
* 0: secret key is invalid
* In: seckey: pointer to a 32-byte secret key
*
int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey);
** Just validate a public key.
* Returns: 1: valid public key
* 0: invalid public key
*
int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen);
** Compute the public key for a secret key.
* In: compressed: whether the computed public key should be compressed
* seckey: pointer to a 32-byte private key.
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
* area to store the public key.
* pubkeylen: pointer to int that will be updated to contains the pubkey's
* length.
* Returns: 1: secret was valid, public key stores
* 0: secret was invalid, try again.
*
int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed);
*/

304
crypto/secp256k1/secp256.go Normal file
View File

@ -0,0 +1,304 @@
package secp256k1
/*
#cgo CFLAGS: -std=gnu99 -Wno-error
#cgo darwin CFLAGS: -I/usr/local/include
#cgo LDFLAGS: -lgmp
#cgo darwin LDFLAGS: -L/usr/local/lib
#define USE_FIELD_10X26
#define USE_NUM_GMP
#define USE_FIELD_INV_BUILTIN
#include "./secp256k1/src/secp256k1.c"
*/
import "C"
import (
"bytes"
"errors"
"unsafe"
)
//#define USE_FIELD_5X64
/*
Todo:
> Centralize key management in module
> add pubkey/private key struct
> Dont let keys leave module; address keys as ints
> store private keys in buffer and shuffle (deters persistance on swap disc)
> Byte permutation (changing)
> xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?)
On Disk
> Store keys in wallets
> use slow key derivation function for wallet encryption key (2 seconds)
*/
func init() {
C.secp256k1_start() //takes 10ms to 100ms
}
func Stop() {
C.secp256k1_stop()
}
/*
int secp256k1_ecdsa_pubkey_create(
unsigned char *pubkey, int *pubkeylen,
const unsigned char *seckey, int compressed);
*/
/** Compute the public key for a secret key.
* In: compressed: whether the computed public key should be compressed
* seckey: pointer to a 32-byte private key.
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
* area to store the public key.
* pubkeylen: pointer to int that will be updated to contains the pubkey's
* length.
* Returns: 1: secret was valid, public key stores
* 0: secret was invalid, try again.
*/
//pubkey, seckey
func GenerateKeyPair() ([]byte, []byte) {
pubkey_len := C.int(65)
const seckey_len = 32
var pubkey []byte = make([]byte, pubkey_len)
var seckey []byte = RandByte(seckey_len)
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
ret := C.secp256k1_ecdsa_pubkey_create(
pubkey_ptr, &pubkey_len,
seckey_ptr, 0)
if ret != C.int(1) {
return GenerateKeyPair() //invalid secret, try again
}
return pubkey, seckey
}
func GeneratePubKey(seckey []byte) ([]byte, error) {
pubkey_len := C.int(65)
const seckey_len = 32
var pubkey []byte = make([]byte, pubkey_len)
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
ret := C.secp256k1_ecdsa_pubkey_create(
pubkey_ptr, &pubkey_len,
seckey_ptr, 0)
if ret != C.int(1) {
return nil, errors.New("Unable to generate pubkey from seckey")
}
return pubkey, nil
}
/*
* Create a compact ECDSA signature (64 byte + recovery id).
* Returns: 1: signature created
* 0: nonce invalid, try another one
* In: msg: the message being signed
* msglen: the length of the message being signed
* seckey: pointer to a 32-byte secret key (assumed to be valid)
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
* Out: sig: pointer to a 64-byte array where the signature will be placed.
* recid: pointer to an int, which will be updated to contain the recovery id.
*/
/*
int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen,
unsigned char *sig64,
const unsigned char *seckey,
const unsigned char *nonce,
int *recid);
*/
func Sign(msg []byte, seckey []byte) ([]byte, error) {
//var nonce []byte = RandByte(32)
nonce := make([]byte, 32)
for i := range msg {
nonce[i] = msg[i] ^ seckey[i]
}
var sig []byte = make([]byte, 65)
var recid C.int
var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
var nonce_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&nonce[0]))
var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
if C.secp256k1_ecdsa_seckey_verify(seckey_ptr) != C.int(1) {
return nil, errors.New("Invalid secret key")
}
ret := C.secp256k1_ecdsa_sign_compact(
msg_ptr, C.int(len(msg)),
sig_ptr,
seckey_ptr,
nonce_ptr,
&recid)
sig[64] = byte(int(recid))
if ret != C.int(1) {
// nonce invalid, retry
return Sign(msg, seckey)
}
return sig, nil
}
/*
* Verify an ECDSA secret key.
* Returns: 1: secret key is valid
* 0: secret key is invalid
* In: seckey: pointer to a 32-byte secret key
*/
func VerifySeckeyValidity(seckey []byte) error {
if len(seckey) != 32 {
return errors.New("priv key is not 32 bytes")
}
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
ret := C.secp256k1_ecdsa_seckey_verify(seckey_ptr)
if int(ret) != 1 {
return errors.New("invalid seckey")
}
return nil
}
/*
* Validate a public key.
* Returns: 1: valid public key
* 0: invalid public key
*/
func VerifyPubkeyValidity(pubkey []byte) error {
if len(pubkey) != 65 {
return errors.New("pub key is not 65 bytes")
}
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
ret := C.secp256k1_ecdsa_pubkey_verify(pubkey_ptr, 65)
if int(ret) != 1 {
return errors.New("invalid pubkey")
}
return nil
}
func VerifySignatureValidity(sig []byte) bool {
//64+1
if len(sig) != 65 {
return false
}
//malleability check, highest bit must be 1
if (sig[32] & 0x80) == 0x80 {
return false
}
//recovery id check
if sig[64] >= 4 {
return false
}
return true
}
//for compressed signatures, does not need pubkey
func VerifySignature(msg []byte, sig []byte, pubkey1 []byte) error {
if msg == nil || sig == nil || pubkey1 == nil {
return errors.New("inputs must be non-nil")
}
if len(sig) != 65 {
return errors.New("invalid signature length")
}
if len(pubkey1) != 65 {
return errors.New("Invalid public key length")
}
//to enforce malleability, highest bit of S must be 0
//S starts at 32nd byte
if (sig[32] & 0x80) == 0x80 { //highest bit must be 1
return errors.New("Signature not malleable")
}
if sig[64] >= 4 {
return errors.New("Recover byte invalid")
}
// if pubkey recovered, signature valid
pubkey2, err := RecoverPubkey(msg, sig)
if err != nil {
return err
}
if len(pubkey2) != 65 {
return errors.New("Invalid recovered public key length")
}
if !bytes.Equal(pubkey1, pubkey2) {
return errors.New("Public key does not match recovered public key")
}
return nil
}
/*
int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen,
const unsigned char *sig64,
unsigned char *pubkey, int *pubkeylen,
int compressed, int recid);
*/
/*
* Recover an ECDSA public key from a compact signature.
* Returns: 1: public key succesfully recovered (which guarantees a correct signature).
* 0: otherwise.
* In: msg: the message assumed to be signed
* msglen: the length of the message
* compressed: whether to recover a compressed or uncompressed pubkey
* recid: the recovery id (as returned by ecdsa_sign_compact)
* Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey.
* pubkeylen: pointer to an int that will contain the pubkey length.
*/
//recovers the public key from the signature
//recovery of pubkey means correct signature
func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
if len(sig) != 65 {
return nil, errors.New("Invalid signature length")
}
var pubkey []byte = make([]byte, 65)
var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
var pubkeylen C.int
ret := C.secp256k1_ecdsa_recover_compact(
msg_ptr, C.int(len(msg)),
sig_ptr,
pubkey_ptr, &pubkeylen,
C.int(0), C.int(sig[64]),
)
if ret == C.int(0) {
return nil, errors.New("Failed to recover public key")
} else if pubkeylen != C.int(65) {
return nil, errors.New("Impossible Error: Invalid recovered public key length")
} else {
return pubkey, nil
}
return nil, errors.New("Impossible Error: func RecoverPubkey has reached an unreachable state")
}

View File

@ -0,0 +1,96 @@
package secp256k1
import (
crand "crypto/rand"
"io"
mrand "math/rand"
"os"
"strings"
"time"
)
/*
Note:
- On windows cryto/rand uses CrytoGenRandom which uses RC4 which is insecure
- Android random number generator is known to be insecure.
- Linux uses /dev/urandom , which is thought to be secure and uses entropy pool
Therefore the output is salted.
*/
//finalizer from MurmerHash3
func mmh3f(key uint64) uint64 {
key ^= key >> 33
key *= 0xff51afd7ed558ccd
key ^= key >> 33
key *= 0xc4ceb9fe1a85ec53
key ^= key >> 33
return key
}
//knuth hash
func knuth_hash(in []byte) uint64 {
var acc uint64 = 3074457345618258791
for i := 0; i < len(in); i++ {
acc += uint64(in[i])
acc *= 3074457345618258799
}
return acc
}
var _rand *mrand.Rand
func init() {
var seed1 uint64 = mmh3f(uint64(time.Now().UnixNano()))
var seed2 uint64 = knuth_hash([]byte(strings.Join(os.Environ(), "")))
var seed3 uint64 = mmh3f(uint64(os.Getpid()))
_rand = mrand.New(mrand.NewSource(int64(seed1 ^ seed2 ^ seed3)))
}
func saltByte(buff []byte) []byte {
for i := 0; i < len(buff); i++ {
var v uint64 = uint64(_rand.Int63())
var b byte
for j := 0; j < 8; j++ {
b ^= byte(v & 0xff)
v = v >> 8
}
buff[i] = b
}
return buff
}
//On Unix-like systems, Reader reads from /dev/urandom.
//On Windows systems, Reader uses the CryptGenRandom API.
//use entropy pool etc and cryptographic random number generator
//mix in time
//mix in mix in cpu cycle count
func RandByte(n int) []byte {
buff := make([]byte, n)
ret, err := io.ReadFull(crand.Reader, buff)
if len(buff) != ret || err != nil {
return nil
}
buff2 := RandByteWeakCrypto(n)
for i := 0; i < n; i++ {
buff[i] ^= buff2[2]
}
return buff
}
/*
On Unix-like systems, Reader reads from /dev/urandom.
On Windows systems, Reader uses the CryptGenRandom API.
*/
func RandByteWeakCrypto(n int) []byte {
buff := make([]byte, n)
ret, err := io.ReadFull(crand.Reader, buff)
if len(buff) != ret || err != nil {
return nil
}
return buff
}

View File

@ -0,0 +1,228 @@
package secp256k1
import (
"bytes"
"fmt"
"log"
"testing"
)
const TESTS = 10000 // how many tests
const SigSize = 65 //64+1
func Test_Secp256_00(t *testing.T) {
var nonce []byte = RandByte(32) //going to get bitcoins stolen!
if len(nonce) != 32 {
t.Fatal()
}
}
//tests for Malleability
//highest bit of S must be 0; 32nd byte
func CompactSigTest(sig []byte) {
var b int = int(sig[32])
if b < 0 {
log.Panic()
}
if ((b >> 7) == 1) != ((b & 0x80) == 0x80) {
log.Panic("b= %v b2= %v \n", b, b>>7)
}
if (b & 0x80) == 0x80 {
log.Panic("b= %v b2= %v \n", b, b&0x80)
}
}
//test pubkey/private generation
func Test_Secp256_01(t *testing.T) {
pubkey, seckey := GenerateKeyPair()
if err := VerifySeckeyValidity(seckey); err != nil {
t.Fatal()
}
if err := VerifyPubkeyValidity(pubkey); err != nil {
t.Fatal()
}
}
//test size of messages
func Test_Secp256_02s(t *testing.T) {
pubkey, seckey := GenerateKeyPair()
msg := RandByte(32)
sig, _ := Sign(msg, seckey)
CompactSigTest(sig)
if sig == nil {
t.Fatal("Signature nil")
}
if len(pubkey) != 65 {
t.Fail()
}
if len(seckey) != 32 {
t.Fail()
}
if len(sig) != 64+1 {
t.Fail()
}
if int(sig[64]) > 4 {
t.Fail()
} //should be 0 to 4
}
//test signing message
func Test_Secp256_02(t *testing.T) {
pubkey1, seckey := GenerateKeyPair()
msg := RandByte(32)
sig, _ := Sign(msg, seckey)
if sig == nil {
t.Fatal("Signature nil")
}
pubkey2, _ := RecoverPubkey(msg, sig)
if pubkey2 == nil {
t.Fatal("Recovered pubkey invalid")
}
if bytes.Equal(pubkey1, pubkey2) == false {
t.Fatal("Recovered pubkey does not match")
}
err := VerifySignature(msg, sig, pubkey1)
if err != nil {
t.Fatal("Signature invalid")
}
}
//test pubkey recovery
func Test_Secp256_02a(t *testing.T) {
pubkey1, seckey1 := GenerateKeyPair()
msg := RandByte(32)
sig, _ := Sign(msg, seckey1)
if sig == nil {
t.Fatal("Signature nil")
}
err := VerifySignature(msg, sig, pubkey1)
if err != nil {
t.Fatal("Signature invalid")
}
pubkey2, _ := RecoverPubkey(msg, sig)
if len(pubkey1) != len(pubkey2) {
t.Fatal()
}
for i, _ := range pubkey1 {
if pubkey1[i] != pubkey2[i] {
t.Fatal()
}
}
if bytes.Equal(pubkey1, pubkey2) == false {
t.Fatal()
}
}
//test random messages for the same pub/private key
func Test_Secp256_03(t *testing.T) {
_, seckey := GenerateKeyPair()
for i := 0; i < TESTS; i++ {
msg := RandByte(32)
sig, _ := Sign(msg, seckey)
CompactSigTest(sig)
sig[len(sig)-1] %= 4
pubkey2, _ := RecoverPubkey(msg, sig)
if pubkey2 == nil {
t.Fail()
}
}
}
//test random messages for different pub/private keys
func Test_Secp256_04(t *testing.T) {
for i := 0; i < TESTS; i++ {
pubkey1, seckey := GenerateKeyPair()
msg := RandByte(32)
sig, _ := Sign(msg, seckey)
CompactSigTest(sig)
if sig[len(sig)-1] >= 4 {
t.Fail()
}
pubkey2, _ := RecoverPubkey(msg, sig)
if pubkey2 == nil {
t.Fail()
}
if bytes.Equal(pubkey1, pubkey2) == false {
t.Fail()
}
}
}
//test random signatures against fixed messages; should fail
//crashes:
// -SIPA look at this
func randSig() []byte {
sig := RandByte(65)
sig[32] &= 0x70
sig[64] %= 4
return sig
}
func Test_Secp256_06a_alt0(t *testing.T) {
pubkey1, seckey := GenerateKeyPair()
msg := RandByte(32)
sig, _ := Sign(msg, seckey)
if sig == nil {
t.Fail()
}
if len(sig) != 65 {
t.Fail()
}
for i := 0; i < TESTS; i++ {
sig = randSig()
pubkey2, _ := RecoverPubkey(msg, sig)
if bytes.Equal(pubkey1, pubkey2) == true {
t.Fail()
}
if pubkey2 != nil && VerifySignature(msg, sig, pubkey2) != nil {
t.Fail()
}
if VerifySignature(msg, sig, pubkey1) == nil {
t.Fail()
}
}
}
//test random messages against valid signature: should fail
func Test_Secp256_06b(t *testing.T) {
pubkey1, seckey := GenerateKeyPair()
msg := RandByte(32)
sig, _ := Sign(msg, seckey)
fail_count := 0
for i := 0; i < TESTS; i++ {
msg = RandByte(32)
pubkey2, _ := RecoverPubkey(msg, sig)
if bytes.Equal(pubkey1, pubkey2) == true {
t.Fail()
}
if pubkey2 != nil && VerifySignature(msg, sig, pubkey2) != nil {
t.Fail()
}
if VerifySignature(msg, sig, pubkey1) == nil {
t.Fail()
}
}
if fail_count != 0 {
fmt.Printf("ERROR: Accepted signature for %v of %v random messages\n", fail_count, TESTS)
}
}

View File

@ -0,0 +1,19 @@
Copyright (c) 2013 Pieter Wuille
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,55 @@
$(shell CC=$(CC) YASM=$(YASM) ./configure)
include config.mk
FILES := src/*.h src/impl/*.h
JAVA_FILES := src/java/org_bitcoin_NativeSecp256k1.h src/java/org_bitcoin_NativeSecp256k1.c
OBJS :=
ifeq ($(USE_ASM), 1)
OBJS := $(OBJS) obj/field_5x$(HAVE_LIMB)_asm.o
endif
STD="gnu99"
default: tests libsecp256k1.a libsecp256k1.so
clean:
rm -rf obj/*.o bench tests *.a *.so config.mk
obj/field_5x52_asm.o: src/field_5x52_asm.asm
$(YASM) -f elf64 -o obj/field_5x52_asm.o src/field_5x52_asm.asm
obj/field_5x64_asm.o: src/field_5x64_asm.asm
$(YASM) -f elf64 -o obj/field_5x64_asm.o src/field_5x64_asm.asm
obj/secp256k1.o: $(FILES) src/secp256k1.c include/secp256k1.h
$(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) -DNDEBUG -$(OPTLEVEL) src/secp256k1.c -c -o obj/secp256k1.o
bench: $(FILES) src/bench.c $(OBJS)
$(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DNDEBUG -$(OPTLEVEL) src/bench.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o bench
tests: $(FILES) src/tests.c $(OBJS)
$(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY -fstack-protector-all -$(OPTLEVEL) -ggdb3 src/tests.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests
tests_fuzzer: $(FILES) src/tests_fuzzer.c obj/secp256k1.o $(OBJS)
$(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY -fstack-protector-all -$(OPTLEVEL) -ggdb3 src/tests_fuzzer.c $(OBJS) obj/secp256k1.o $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests_fuzzer
coverage: $(FILES) src/tests.c $(OBJS)
rm -rf tests.gcno tests.gcda tests_cov
$(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY --coverage -$(OPTLEVEL) -g src/tests.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests_cov
rm -rf lcov
mkdir -p lcov
cd lcov; lcov --directory ../ --zerocounters
cd lcov; ../tests_cov
cd lcov; lcov --directory ../ --capture --output-file secp256k1.info
cd lcov; genhtml -o . secp256k1.info
libsecp256k1.a: obj/secp256k1.o $(OBJS)
$(AR) -rs $@ $(OBJS) obj/secp256k1.o
libsecp256k1.so: obj/secp256k1.o $(OBJS)
$(CC) -std=$(STD) $(LDFLAGS_EXTRA) $(OBJS) obj/secp256k1.o -shared -o libsecp256k1.so
libjavasecp256k1.so: $(OBJS) obj/secp256k1.o $(JAVA_FILES)
$(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) -DNDEBUG -$(OPTLEVEL) -I. src/java/org_bitcoin_NativeSecp256k1.c $(LDFLAGS_EXTRA) $(OBJS) obj/secp256k1.o -shared -o libjavasecp256k1.so

View File

@ -0,0 +1,3 @@
* Unit tests for fieldelem/groupelem, including ones intended to
trigger fieldelem's boundary cases.
* Complete constant-time operations for signing/keygen

View File

@ -0,0 +1,9 @@
CC=cc
YASM=yasm
CFLAGS_EXTRA=-DUSE_FIELD_5X52 -DUSE_FIELD_5X52_ASM -DUSE_NUM_GMP -DUSE_FIELD_INV_NUM
CFLAGS_TEST_EXTRA=-DENABLE_OPENSSL_TESTS
LDFLAGS_EXTRA=-lgmp
LDFLAGS_TEST_EXTRA=-lcrypto
USE_ASM=1
HAVE_LIMB=52
OPTLEVEL=O2

175
crypto/secp256k1/secp256k1/configure vendored Executable file
View File

@ -0,0 +1,175 @@
#!/bin/sh
if test -f config.mk; then
exit 0
fi
if test -z "$CC"; then
CC=cc
fi
if test -z "$YASM"; then
YASM=yasm
fi
# test yasm
$YASM -f elf64 -o /tmp/secp256k1-$$.o - <<EOF
BITS 64
GLOBAL testyasm
ALIGN 32
testyasm:
xor r9,r9
EOF
if [ "$?" = 0 ]; then
$CC $CFLAGS -std=c99 -x c -c - -o /tmp/secp256k1-$$-2.o 2>/dev/null <<EOF
void __attribute__ ((sysv_abi)) testyasm(void);
int main() {
testyasm();
return 0;
}
EOF
$CC $CFLAGS -std=c99 /tmp/secp256k1-$$-2.o /tmp/secp256k1-$$.o -o /dev/null 2>/dev/null
if [ "$?" = 0 ]; then
HAVE_YASM=1
fi
rm -rf /tmp/secp256k1-$$-2.o /tmp/secp256k1-$$.o
fi
# test openssl
HAVE_OPENSSL=0
$CC $CFLAGS -std=c99 -x c - -o /dev/null -lcrypto 2>/dev/null <<EOF
#include <openssl/bn.h>
int main() {
BN_CTX *ctx = BN_CTX_new();
BN_CTX_free(ctx);
return 0;
}
EOF
if [ "$?" = 0 ]; then
HAVE_OPENSSL=1
fi
# test openssl/EC
HAVE_OPENSSL_EC=0
if [ "$HAVE_OPENSSL" = "1" ]; then
$CC $CFLAGS -std=c99 -x c - -o /dev/null -lcrypto 2>/dev/null <<EOF
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
int main() {
EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
EC_KEY_free(eckey);
return 0;
}
EOF
if [ "$?" = 0 ]; then
HAVE_OPENSSL_EC=1
fi
fi
# test gmp
HAVE_GMP=0
$CC $CFLAGS -std=c99 -x c - -o /dev/null -lgmp 2>/dev/null <<EOF
#include <gmp.h>
int main() {
mpz_t n;
mpz_init(n);
mpz_clear(n);
return 0;
}
EOF
if [ "$?" = 0 ]; then
HAVE_GMP=1
fi
# test __int128
HAVE_INT128=0
$CC $CFLAGS -std=c99 -x c - -o /dev/null 2>/dev/null <<EOF
#include <stdint.h>
int main() {
__int128 x = 0;
return 0;
}
EOF
if [ "$?" = 0 ]; then
HAVE_INT128=1
fi
#default limb size
HAVE_LIMB=52
for arg in "$@"; do
case "$arg" in
--no-yasm)
HAVE_YASM=0
;;
--no-gmp)
HAVE_GMP=0
;;
--no-openssl)
HAVE_OPENSSL=0
;;
--use-5x64)
HAVE_LIMB=64
;;
esac
done
LINK_OPENSSL=0
LINK_GMP=0
USE_ASM=0
# select field implementation
if [ "$HAVE_YASM" = "1" ]; then
CFLAGS_FIELD="-DUSE_FIELD_5X$HAVE_LIMB -DUSE_FIELD_5X${HAVE_LIMB}_ASM"
USE_ASM=1
elif [ "$HAVE_INT128" = "1" ]; then
CFLAGS_FIELD="-DUSE_FIELD_5X$HAVE_LIMB -DUSE_FIELD_5X${HAVE_LIMB}_INT128"
elif [ "$HAVE_GMP" = "1" ]; then
CFLAGS_FIELD="-DUSE_FIELD_GMP"
LINK_GMP=1
else
CFLAGS_FIELD="-DUSE_FIELD_10X26"
fi
# select num implementation
if [ "$HAVE_GMP" = "1" ]; then
CFLAGS_NUM="-DUSE_NUM_GMP -DUSE_FIELD_INV_NUM"
LINK_GMP=1
elif [ "$HAVE_OPENSSL" = "1" ]; then
CFLAGS_NUM="-DUSE_NUM_OPENSSL -DUSE_FIELD_INV_BUILTIN"
LINK_OPENSSL=1
else
echo "No usable num implementation found" >&2
exit 1
fi
CFLAGS_EXTRA="$CFLAGS_FIELD $CFLAGS_NUM"
LDFLAGS_EXTRA=""
if [ "$LINK_GMP" = "1" ]; then
LDFLAGS_EXTRA="-lgmp"
fi
if [ "$LINK_OPENSSL" = "1" ]; then
LDFLAGS_EXTRA="-lcrypto"
else
if [ "$HAVE_OPENSSL_EC" = "1" ]; then
LDFLAGS_TEST_EXTRA="-lcrypto"
fi
fi
CFLAGS_TEST_EXTRA=""
if [ "$HAVE_OPENSSL_EC" = "1" ]; then
CFLAGS_TEST_EXTRA="-DENABLE_OPENSSL_TESTS"
fi
echo "CC=$CC" > config.mk
echo "YASM=$YASM" >>config.mk
echo "CFLAGS_EXTRA=$CFLAGS_EXTRA" >> config.mk
echo "CFLAGS_TEST_EXTRA=$CFLAGS_TEST_EXTRA" >> config.mk
echo "LDFLAGS_EXTRA=$LDFLAGS_EXTRA" >> config.mk
echo "LDFLAGS_TEST_EXTRA=$LDFLAGS_TEST_EXTRA" >> config.mk
echo "USE_ASM=$USE_ASM" >>config.mk
echo "HAVE_LIMB=$HAVE_LIMB" >>config.mk
echo "OPTLEVEL=O2" >>config.mk

View File

@ -0,0 +1,121 @@
#ifndef _SECP256K1_
#define _SECP256K1_
#ifdef __cplusplus
extern "C" {
#endif
/** Initialize the library. This may take some time (10-100 ms).
* You need to call this before calling any other function.
* It cannot run in parallel with any other functions, but once
* secp256k1_start() returns, all other functions are thread-safe.
*/
void secp256k1_start(void);
/** Free all memory associated with this library. After this, no
* functions can be called anymore, except secp256k1_start()
*/
void secp256k1_stop(void);
/** Verify an ECDSA signature.
* Returns: 1: correct signature
* 0: incorrect signature
* -1: invalid public key
* -2: invalid signature
*/
int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen,
const unsigned char *sig, int siglen,
const unsigned char *pubkey, int pubkeylen);
/** Create an ECDSA signature.
* Returns: 1: signature created
* 0: nonce invalid, try another one
* In: msg: the message being signed
* msglen: the length of the message being signed
* seckey: pointer to a 32-byte secret key (assumed to be valid)
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
* Out: sig: pointer to a 72-byte array where the signature will be placed.
* siglen: pointer to an int, which will be updated to the signature length (<=72).
*/
int secp256k1_ecdsa_sign(const unsigned char *msg, int msglen,
unsigned char *sig, int *siglen,
const unsigned char *seckey,
const unsigned char *nonce);
/** Create a compact ECDSA signature (64 byte + recovery id).
* Returns: 1: signature created
* 0: nonce invalid, try another one
* In: msg: the message being signed
* msglen: the length of the message being signed
* seckey: pointer to a 32-byte secret key (assumed to be valid)
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
* Out: sig: pointer to a 64-byte array where the signature will be placed.
* recid: pointer to an int, which will be updated to contain the recovery id.
*/
int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen,
unsigned char *sig64,
const unsigned char *seckey,
const unsigned char *nonce,
int *recid);
/** Recover an ECDSA public key from a compact signature.
* Returns: 1: public key succesfully recovered (which guarantees a correct signature).
* 0: otherwise.
* In: msg: the message assumed to be signed
* msglen: the length of the message
* sig64: signature as 64 byte array
* compressed: whether to recover a compressed or uncompressed pubkey
* recid: the recovery id (as returned by ecdsa_sign_compact)
* Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey.
* pubkeylen: pointer to an int that will contain the pubkey length.
*/
int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen,
const unsigned char *sig64,
unsigned char *pubkey, int *pubkeylen,
int compressed, int recid);
/** Verify an ECDSA secret key.
* Returns: 1: secret key is valid
* 0: secret key is invalid
* In: seckey: pointer to a 32-byte secret key
*/
int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey);
/** Just validate a public key.
* Returns: 1: valid public key
* 0: invalid public key
*/
int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen);
/** Compute the public key for a secret key.
* In: compressed: whether the computed public key should be compressed
* seckey: pointer to a 32-byte private key.
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
* area to store the public key.
* pubkeylen: pointer to int that will be updated to contains the pubkey's
* length.
* Returns: 1: secret was valid, public key stores
* 0: secret was invalid, try again.
*/
int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed);
int secp256k1_ecdsa_pubkey_decompress(unsigned char *pubkey, int *pubkeylen);
int secp256k1_ecdsa_privkey_export(const unsigned char *seckey,
unsigned char *privkey, int *privkeylen,
int compressed);
int secp256k1_ecdsa_privkey_import(unsigned char *seckey,
const unsigned char *privkey, int privkeylen);
int secp256k1_ecdsa_privkey_tweak_add(unsigned char *seckey, const unsigned char *tweak);
int secp256k1_ecdsa_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak);
int secp256k1_ecdsa_privkey_tweak_mul(unsigned char *seckey, const unsigned char *tweak);
int secp256k1_ecdsa_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,64 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <stdio.h>
#include "impl/num.h"
#include "impl/field.h"
#include "impl/group.h"
#include "impl/ecmult.h"
#include "impl/ecdsa.h"
#include "impl/util.h"
void random_num_order(secp256k1_num_t *num) {
do {
unsigned char b32[32];
secp256k1_rand256(b32);
secp256k1_num_set_bin(num, b32, 32);
if (secp256k1_num_is_zero(num))
continue;
if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
continue;
break;
} while(1);
}
int main() {
secp256k1_fe_start();
secp256k1_ge_start();
secp256k1_ecmult_start();
secp256k1_fe_t x;
const secp256k1_num_t *order = &secp256k1_ge_consts->order;
secp256k1_num_t r, s, m;
secp256k1_num_init(&r);
secp256k1_num_init(&s);
secp256k1_num_init(&m);
secp256k1_ecdsa_sig_t sig;
secp256k1_ecdsa_sig_init(&sig);
secp256k1_fe_set_hex(&x, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
int cnt = 0;
int good = 0;
for (int i=0; i<1000000; i++) {
random_num_order(&r);
random_num_order(&s);
random_num_order(&m);
secp256k1_ecdsa_sig_set_rs(&sig, &r, &s);
secp256k1_ge_t pubkey; secp256k1_ge_set_xo(&pubkey, &x, 1);
if (secp256k1_ge_is_valid(&pubkey)) {
cnt++;
good += secp256k1_ecdsa_sig_verify(&sig, &pubkey, &m);
}
}
printf("%i/%i\n", good, cnt);
secp256k1_num_free(&r);
secp256k1_num_free(&s);
secp256k1_num_free(&m);
secp256k1_ecdsa_sig_free(&sig);
secp256k1_ecmult_stop();
secp256k1_ge_stop();
secp256k1_fe_stop();
return 0;
}

View File

@ -0,0 +1,28 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_ECDSA_
#define _SECP256K1_ECDSA_
#include "num.h"
typedef struct {
secp256k1_num_t r, s;
} secp256k1_ecdsa_sig_t;
void static secp256k1_ecdsa_sig_init(secp256k1_ecdsa_sig_t *r);
void static secp256k1_ecdsa_sig_free(secp256k1_ecdsa_sig_t *r);
int static secp256k1_ecdsa_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size);
void static secp256k1_ecdsa_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed);
int static secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size);
int static secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a);
int static secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message);
int static secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *seckey, const secp256k1_num_t *message, const secp256k1_num_t *nonce, int *recid);
int static secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid);
void static secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s);
int static secp256k1_ecdsa_privkey_parse(secp256k1_num_t *key, const unsigned char *privkey, int privkeylen);
int static secp256k1_ecdsa_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_num_t *key, int compressed);
#endif

View File

@ -0,0 +1,19 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_ECMULT_
#define _SECP256K1_ECMULT_
#include "num.h"
#include "group.h"
static void secp256k1_ecmult_start(void);
static void secp256k1_ecmult_stop(void);
/** Multiply with the generator: R = a*G */
static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *a);
/** Double multiply: R = na*A + ng*G */
static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng);
#endif

View File

@ -0,0 +1,101 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_
#define _SECP256K1_FIELD_
/** Field element module.
*
* Field elements can be represented in several ways, but code accessing
* it (and implementations) need to take certain properaties into account:
* - Each field element can be normalized or not.
* - Each field element has a magnitude, which represents how far away
* its representation is away from normalization. Normalized elements
* always have a magnitude of 1, but a magnitude of 1 doesn't imply
* normality.
*/
#if defined(USE_FIELD_GMP)
#include "field_gmp.h"
#elif defined(USE_FIELD_10X26)
#include "field_10x26.h"
#elif defined(USE_FIELD_5X52)
#include "field_5x52.h"
#elif defined(USE_FIELD_5X64)
#include "field_5x64.h"
#else
#error "Please select field implementation"
#endif
typedef struct {
secp256k1_num_t p;
} secp256k1_fe_consts_t;
static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL;
/** Initialize field element precomputation data. */
void static secp256k1_fe_start(void);
/** Unload field element precomputation data. */
void static secp256k1_fe_stop(void);
/** Normalize a field element. */
void static secp256k1_fe_normalize(secp256k1_fe_t *r);
/** Set a field element equal to a small integer. Resulting field element is normalized. */
void static secp256k1_fe_set_int(secp256k1_fe_t *r, int a);
/** Verify whether a field element is zero. Requires the input to be normalized. */
int static secp256k1_fe_is_zero(const secp256k1_fe_t *a);
/** Check the "oddness" of a field element. Requires the input to be normalized. */
int static secp256k1_fe_is_odd(const secp256k1_fe_t *a);
/** Compare two field elements. Requires both inputs to be normalized */
int static secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b);
/** Set a field element equal to 32-byte big endian value. Resulting field element is normalized. */
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a);
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a);
/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input
* as an argument. The magnitude of the output is one higher. */
void static secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m);
/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
* small integer. */
void static secp256k1_fe_mul_int(secp256k1_fe_t *r, int a);
/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
void static secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.
* The output magnitude is 1 (but not guaranteed to be normalized). */
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b);
/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.
* The output magnitude is 1 (but not guaranteed to be normalized). */
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Sets a field element to be the (modular) square root of another. Requires the inputs' magnitude to
* be at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
* at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
void static secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Convert a field element to a hexadecimal string. */
void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a);
/** Convert a hexadecimal string to a field element. */
void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen);
#endif

View File

@ -0,0 +1,19 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_
#include <stdint.h>
typedef struct {
// X = sum(i=0..9, elem[i]*2^26) mod n
uint32_t n[10];
#ifdef VERIFY
int magnitude;
int normalized;
#endif
} secp256k1_fe_t;
#endif

View File

@ -0,0 +1,19 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_
#include <stdint.h>
typedef struct {
// X = sum(i=0..4, elem[i]*2^52) mod n
uint64_t n[5];
#ifdef VERIFY
int magnitude;
int normalized;
#endif
} secp256k1_fe_t;
#endif

View File

@ -0,0 +1,463 @@
;; Added by Diederik Huys, March 2013
;;
;; Provided public procedures:
;; secp256k1_fe_mul_inner
;; secp256k1_fe_sqr_inner
;;
;; Needed tools: YASM (http://yasm.tortall.net)
;;
;;
BITS 64
;; Procedure ExSetMult
;; Register Layout:
;; INPUT: rdi = a->n
;; rsi = b->n
;; rdx = r->a
;;
;; INTERNAL: rdx:rax = multiplication accumulator
;; r9:r8 = c
;; r10-r13 = t0-t3
;; r14 = b.n[0] / t4
;; r15 = b.n[1] / t5
;; rbx = b.n[2] / t6
;; rcx = b.n[3] / t7
;; rbp = Constant 0FFFFFFFFFFFFFh / t8
;; rsi = b.n / b.n[4] / t9
GLOBAL secp256k1_fe_mul_inner
ALIGN 32
secp256k1_fe_mul_inner:
push rbp
push rbx
push r12
push r13
push r14
push r15
push rdx
mov r14,[rsi+8*0] ; preload b.n[0]. This will be the case until
; b.n[0] is no longer needed, then we reassign
; r14 to t4
;; c=a.n[0] * b.n[0]
mov rax,[rdi+0*8] ; load a.n[0]
mov rbp,0FFFFFFFFFFFFFh
mul r14 ; rdx:rax=a.n[0]*b.n[0]
mov r15,[rsi+1*8]
mov r10,rbp ; load modulus into target register for t0
mov r8,rax
and r10,rax ; only need lower qword of c
shrd r8,rdx,52
xor r9,r9 ; c < 2^64, so we ditch the HO part
;; c+=a.n[0] * b.n[1] + a.n[1] * b.n[0]
mov rax,[rdi+0*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul r14
mov r11,rbp
mov rbx,[rsi+2*8]
add r8,rax
adc r9,rdx
and r11,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[0 1 2] * b.n[2 1 0]
mov rax,[rdi+0*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul r14
mov r12,rbp
mov rcx,[rsi+3*8]
add r8,rax
adc r9,rdx
and r12,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[0 1 2 3] * b.n[3 2 1 0]
mov rax,[rdi+0*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul r14
mov r13,rbp
mov rsi,[rsi+4*8] ; load b.n[4] and destroy pointer
add r8,rax
adc r9,rdx
and r13,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[0 1 2 3 4] * b.n[4 3 2 1 0]
mov rax,[rdi+0*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul r14
mov r14,rbp ; load modulus into t4 and destroy a.n[0]
add r8,rax
adc r9,rdx
and r14,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[1 2 3 4] * b.n[4 3 2 1]
mov rax,[rdi+1*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul r15
mov r15,rbp
add r8,rax
adc r9,rdx
and r15,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[2 3 4] * b.n[4 3 2]
mov rax,[rdi+2*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul rbx
mov rbx,rbp
add r8,rax
adc r9,rdx
and rbx,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[3 4] * b.n[4 3]
mov rax,[rdi+3*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul rcx
mov rcx,rbp
add r8,rax
adc r9,rdx
and rcx,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[4] * b.n[4]
mov rax,[rdi+4*8]
mul rsi
;; mov rbp,rbp ; modulus already there!
add r8,rax
adc r9,rdx
and rbp,r8
shrd r8,r9,52
xor r9,r9
mov rsi,r8 ; load c into t9 and destroy b.n[4]
;; *******************************************************
common_exit_norm:
mov rdi,01000003D10h ; load constant
mov rax,r15 ; get t5
mul rdi
add rax,r10 ; +t0
adc rdx,0
mov r10,0FFFFFFFFFFFFFh ; modulus. Sadly, we ran out of registers!
mov r8,rax ; +c
and r10,rax
shrd r8,rdx,52
xor r9,r9
mov rax,rbx ; get t6
mul rdi
add rax,r11 ; +t1
adc rdx,0
mov r11,0FFFFFFFFFFFFFh ; modulus
add r8,rax ; +c
adc r9,rdx
and r11,r8
shrd r8,r9,52
xor r9,r9
mov rax,rcx ; get t7
mul rdi
add rax,r12 ; +t2
adc rdx,0
pop rbx ; retrieve pointer to this.n
mov r12,0FFFFFFFFFFFFFh ; modulus
add r8,rax ; +c
adc r9,rdx
and r12,r8
mov [rbx+2*8],r12 ; mov into this.n[2]
shrd r8,r9,52
xor r9,r9
mov rax,rbp ; get t8
mul rdi
add rax,r13 ; +t3
adc rdx,0
mov r13,0FFFFFFFFFFFFFh ; modulus
add r8,rax ; +c
adc r9,rdx
and r13,r8
mov [rbx+3*8],r13 ; -> this.n[3]
shrd r8,r9,52
xor r9,r9
mov rax,rsi ; get t9
mul rdi
add rax,r14 ; +t4
adc rdx,0
mov r14,0FFFFFFFFFFFFh ; !!!
add r8,rax ; +c
adc r9,rdx
and r14,r8
mov [rbx+4*8],r14 ; -> this.n[4]
shrd r8,r9,48 ; !!!
xor r9,r9
mov rax,01000003D1h
mul r8
add rax,r10
adc rdx,0
mov r10,0FFFFFFFFFFFFFh ; modulus
mov r8,rax
and rax,r10
shrd r8,rdx,52
mov [rbx+0*8],rax ; -> this.n[0]
add r8,r11
mov [rbx+1*8],r8 ; -> this.n[1]
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret
;; PROC ExSetSquare
;; Register Layout:
;; INPUT: rdi = a.n
;; rsi = this.a
;; INTERNAL: rdx:rax = multiplication accumulator
;; r9:r8 = c
;; r10-r13 = t0-t3
;; r14 = a.n[0] / t4
;; r15 = a.n[1] / t5
;; rbx = a.n[2] / t6
;; rcx = a.n[3] / t7
;; rbp = 0FFFFFFFFFFFFFh / t8
;; rsi = a.n[4] / t9
GLOBAL secp256k1_fe_sqr_inner
ALIGN 32
secp256k1_fe_sqr_inner:
push rbp
push rbx
push r12
push r13
push r14
push r15
push rsi
mov rbp,0FFFFFFFFFFFFFh
;; c=a.n[0] * a.n[0]
mov r14,[rdi+0*8] ; r14=a.n[0]
mov r10,rbp ; modulus
mov rax,r14
mul rax
mov r15,[rdi+1*8] ; a.n[1]
add r14,r14 ; r14=2*a.n[0]
mov r8,rax
and r10,rax ; only need lower qword
shrd r8,rdx,52
xor r9,r9
;; c+=2*a.n[0] * a.n[1]
mov rax,r14 ; r14=2*a.n[0]
mul r15
mov rbx,[rdi+2*8] ; rbx=a.n[2]
mov r11,rbp ; modulus
add r8,rax
adc r9,rdx
and r11,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[0]*a.n[2]+a.n[1]*a.n[1]
mov rax,r14
mul rbx
add r8,rax
adc r9,rdx
mov rax,r15
mov r12,rbp ; modulus
mul rax
mov rcx,[rdi+3*8] ; rcx=a.n[3]
add r15,r15 ; r15=a.n[1]*2
add r8,rax
adc r9,rdx
and r12,r8 ; only need lower dword
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[0]*a.n[3]+2*a.n[1]*a.n[2]
mov rax,r14
mul rcx
add r8,rax
adc r9,rdx
mov rax,r15 ; rax=2*a.n[1]
mov r13,rbp ; modulus
mul rbx
mov rsi,[rdi+4*8] ; rsi=a.n[4]
add r8,rax
adc r9,rdx
and r13,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[0]*a.n[4]+2*a.n[1]*a.n[3]+a.n[2]*a.n[2]
mov rax,r14 ; last time we need 2*a.n[0]
mul rsi
add r8,rax
adc r9,rdx
mov rax,r15
mul rcx
mov r14,rbp ; modulus
add r8,rax
adc r9,rdx
mov rax,rbx
mul rax
add rbx,rbx ; rcx=2*a.n[2]
add r8,rax
adc r9,rdx
and r14,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[1]*a.n[4]+2*a.n[2]*a.n[3]
mov rax,r15 ; last time we need 2*a.n[1]
mul rsi
add r8,rax
adc r9,rdx
mov rax,rbx
mul rcx
mov r15,rbp ; modulus
add r8,rax
adc r9,rdx
and r15,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[2]*a.n[4]+a.n[3]*a.n[3]
mov rax,rbx ; last time we need 2*a.n[2]
mul rsi
add r8,rax
adc r9,rdx
mov rax,rcx ; a.n[3]
mul rax
mov rbx,rbp ; modulus
add r8,rax
adc r9,rdx
and rbx,r8 ; only need lower dword
lea rax,[2*rcx]
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[3]*a.n[4]
mul rsi
mov rcx,rbp ; modulus
add r8,rax
adc r9,rdx
and rcx,r8 ; only need lower dword
shrd r8,r9,52
xor r9,r9
;; c+=a.n[4]*a.n[4]
mov rax,rsi
mul rax
;; mov rbp,rbp ; modulus is already there!
add r8,rax
adc r9,rdx
and rbp,r8
shrd r8,r9,52
xor r9,r9
mov rsi,r8
;; *******************************************************
jmp common_exit_norm
end

View File

@ -0,0 +1,19 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_
#include <stdint.h>
typedef struct {
// X = sum(i=0..4, elem[i]*2^64) mod n
uint64_t n[5];
#ifdef VERIFY
int reduced; // n[4] == 0
int normalized; // reduced and X < 2^256 - 0x100003D1
#endif
} secp256k1_fe_t;
#endif

View File

@ -0,0 +1,332 @@
;; Added by Diederik Huys, March 2013
;;
;; Provided public procedures:
;; secp256k1_fe_mul_inner
;; secp256k1_fe_sqr_inner
;;
;; Needed tools: YASM (http://yasm.tortall.net)
;;
;;
BITS 64
COMP_LIMB EQU 000000001000003D1h
;; Procedure ExSetMult
;; Register Layout:
;; INPUT: rdi = a->n
;; rsi = b->n
;; rdx = r->a
;;
;; INTERNAL: rdx:rax = multiplication accumulator
;; r8-r10 = c0-c2
;; r11-r15 = b.n[0]-b.n[4] / r3 - r7
;; rbx = r0
;; rcx = r1
;; rbp = r2
;;
GLOBAL secp256k1_fe_mul_inner
ALIGN 32
secp256k1_fe_mul_inner:
push rbp
push rbx
push r12
push r13
push r14
push r15
push rdx
mov r11,[rsi+8*0] ; preload b.n[0]
;; step 1: mul_c2
mov rax,[rdi+0*8] ; load a.n[0]
mul r11 ; rdx:rax=a.n[0]*b.n[0]
mov r12,[rsi+1*8] ; preload b.n[1]
mov rbx,rax ; retire LO qword (r[0])
mov r8,rdx ; save overflow
xor r9,r9 ; overflow HO qwords
xor r10,r10
;; c+=a.n[0] * b.n[1] + a.n[1] * b.n[0]
mov rax,[rdi+0*8]
mul r12
mov r13,[rsi+2*8] ; preload b.n[2]
add r8,rax ; still the same :-)
adc r9,rdx ;
adc r10,0 ; mmm...
mov rax,[rdi+1*8]
mul r11
add r8,rax
adc r9,rdx
adc r10,0
mov rcx,r8 ; retire r[1]
xor r8,r8
;; c+=a.n[0 1 2] * b.n[2 1 0]
mov rax,[rdi+0*8]
mul r13
mov r14,[rsi+3*8] ; preload b.n[3]
add r9,rax
adc r10,rdx
adc r8,0
mov rax,[rdi+1*8]
mul r12
add r9,rax
adc r10,rdx
adc r8,0
mov rax,[rdi+2*8]
mul r11
add r9,rax
adc r10,rdx
adc r8,0
mov rbp,r9 ; retire r[2]
xor r9,r9
;; c+=a.n[0 1 2 3] * b.n[3 2 1 0]
mov rax,[rdi+0*8]
mul r14
add r10,rax
adc r8,rdx
adc r9,0
mov rax,[rdi+1*8]
mul r13
add r10,rax
adc r8,rdx
adc r9,0
mov rax,[rdi+2*8]
mul r12
add r10,rax
adc r8,rdx
adc r9,0
mov rax,[rdi+3*8]
mul r11
add r10,rax
adc r8,rdx
adc r9,0
mov r11,r10 ; retire r[3]
xor r10,r10
;; c+=a.n[1 2 3] * b.n[3 2 1]
mov rax,[rdi+1*8]
mul r14
add r8,rax
adc r9,rdx
adc r10,0
mov rax,[rdi+2*8]
mul r13
add r8,rax
adc r9,rdx
adc r10,0
mov rax,[rdi+3*8]
mul r12
add r8,rax
adc r9,rdx
adc r10,0
mov r12,r8 ; retire r[4]
xor r8,r8
;; c+=a.n[2 3] * b.n[3 2]
mov rax,[rdi+2*8]
mul r14
add r9,rax ; still the same :-)
adc r10,rdx ;
adc r8,0 ; mmm...
mov rax,[rdi+3*8]
mul r13
add r9,rax
adc r10,rdx
adc r8,0
mov r13,r9 ; retire r[5]
xor r9,r9
;; c+=a.n[3] * b.n[3]
mov rax,[rdi+3*8]
mul r14
add r10,rax
adc r8,rdx
mov r14,r10
mov r15,r8
;; *******************************************************
common_exit_norm:
mov rdi,COMP_LIMB
mov rax,r12
mul rdi
add rax,rbx
adc rcx,rdx
pop rbx
mov [rbx],rax
mov rax,r13 ; get r5
mul rdi
add rax,rcx ; +r1
adc rbp,rdx
mov [rbx+1*8],rax
mov rax,r14 ; get r6
mul rdi
add rax,rbp ; +r2
adc r11,rdx
mov [rbx+2*8],rax
mov rax,r15 ; get r7
mul rdi
add rax,r11 ; +r3
adc rdx,0
mov [rbx+3*8],rax
mov [rbx+4*8],rdx
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret
;; PROC ExSetSquare
;; Register Layout:
;; INPUT: rdi = a.n
;; rsi = this.a
;; INTERNAL: rdx:rax = multiplication accumulator
;; r8-r10 = c
;; r11-r15 = a.n[0]-a.n[4] / r3-r7
;; rbx = r0
;; rcx = r1
;; rbp = r2
GLOBAL secp256k1_fe_sqr_inner
ALIGN 32
secp256k1_fe_sqr_inner:
push rbp
push rbx
push r12
push r13
push r14
push r15
push rsi
mov r11,[rdi+8*0] ; preload a.n[0]
;; step 1: mul_c2
mov rax,r11 ; load a.n[0]
mul rax ; rdx:rax=a.n[0]²
mov r12,[rdi+1*8] ; preload a.n[1]
mov rbx,rax ; retire LO qword (r[0])
mov r8,rdx ; save overflow
xor r9,r9 ; overflow HO qwords
xor r10,r10
;; c+=2*a.n[0] * a.n[1]
mov rax,r11 ; load a.n[0]
mul r12 ; rdx:rax=a.n[0] * a.n[1]
mov r13,[rdi+2*8] ; preload a.n[2]
add rax,rax ; rdx:rax*=2
adc rdx,rdx
adc r10,0
add r8,rax ; still the same :-)
adc r9,rdx
adc r10,0 ; mmm...
mov rcx,r8 ; retire r[1]
xor r8,r8
;; c+=2*a.n[0]*a.n[2]+a.n[1]*a.n[1]
mov rax,r11 ; load a.n[0]
mul r13 ; * a.n[2]
mov r14,[rdi+3*8] ; preload a.n[3]
add rax,rax ; rdx:rax*=2
adc rdx,rdx
adc r8,0
add r9,rax
adc r10,rdx
adc r8,0
mov rax,r12
mul rax
add r9,rax
adc r10,rdx
adc r8,0
mov rbp,r9
xor r9,r9
;; c+=2*a.n[0]*a.n[3]+2*a.n[1]*a.n[2]
mov rax,r11 ; load a.n[0]
mul r14 ; * a.n[3]
add rax,rax ; rdx:rax*=2
adc rdx,rdx
adc r9,0
add r10,rax
adc r8,rdx
adc r9,0
mov rax,r12 ; load a.n[1]
mul r13 ; * a.n[2]
add rax,rax
adc rdx,rdx
adc r9,0
add r10,rax
adc r8,rdx
adc r9,0
mov r11,r10
xor r10,r10
;; c+=2*a.n[1]*a.n[3]+a.n[2]*a.n[2]
mov rax,r12 ; load a.n[1]
mul r14 ; * a.n[3]
add rax,rax ; rdx:rax*=2
adc rdx,rdx
adc r10,0
add r8,rax
adc r9,rdx
adc r10,0
mov rax,r13
mul rax
add r8,rax
adc r9,rdx
adc r10,0
mov r12,r8
xor r8,r8
;; c+=2*a.n[2]*a.n[3]
mov rax,r13 ; load a.n[2]
mul r14 ; * a.n[3]
add rax,rax ; rdx:rax*=2
adc rdx,rdx
adc r8,0
add r9,rax
adc r10,rdx
adc r8,0
mov r13,r9
xor r9,r9
;; c+=a.n[3]²
mov rax,r14
mul rax
add r10,rax
adc r8,rdx
mov r14,r10
mov r15,r8
jmp common_exit_norm
end

View File

@ -0,0 +1,16 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_
#include <gmp.h>
#define FIELD_LIMBS ((256 + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
typedef struct {
mp_limb_t n[FIELD_LIMBS+1];
} secp256k1_fe_t;
#endif

View File

@ -0,0 +1,108 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_GROUP_
#define _SECP256K1_GROUP_
#include "num.h"
#include "field.h"
/** A group element of the secp256k1 curve, in affine coordinates. */
typedef struct {
secp256k1_fe_t x;
secp256k1_fe_t y;
int infinity; // whether this represents the point at infinity
} secp256k1_ge_t;
/** A group element of the secp256k1 curve, in jacobian coordinates. */
typedef struct {
secp256k1_fe_t x; // actual X: x/z^2
secp256k1_fe_t y; // actual Y: y/z^3
secp256k1_fe_t z;
int infinity; // whether this represents the point at infinity
} secp256k1_gej_t;
/** Global constants related to the group */
typedef struct {
secp256k1_num_t order; // the order of the curve (= order of its generator)
secp256k1_num_t half_order; // half the order of the curve (= order of its generator)
secp256k1_ge_t g; // the generator point
// constants related to secp256k1's efficiently computable endomorphism
secp256k1_fe_t beta;
secp256k1_num_t lambda, a1b2, b1, a2;
} secp256k1_ge_consts_t;
static const secp256k1_ge_consts_t *secp256k1_ge_consts = NULL;
/** Initialize the group module. */
void static secp256k1_ge_start(void);
/** De-initialize the group module. */
void static secp256k1_ge_stop(void);
/** Set a group element equal to the point at infinity */
void static secp256k1_ge_set_infinity(secp256k1_ge_t *r);
/** Set a group element equal to the point with given X and Y coordinates */
void static secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y);
/** Set a group element (jacobian) equal to the point with given X coordinate, and given oddness for Y.
The result is not guaranteed to be valid. */
void static secp256k1_ge_set_xo(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd);
/** Check whether a group element is the point at infinity. */
int static secp256k1_ge_is_infinity(const secp256k1_ge_t *a);
/** Check whether a group element is valid (i.e., on the curve). */
int static secp256k1_ge_is_valid(const secp256k1_ge_t *a);
void static secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a);
/** Get a hex representation of a point. *rlen will be overwritten with the real length. */
void static secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a);
/** Set a group element equal to another which is given in jacobian coordinates */
void static secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a);
/** Set a group element (jacobian) equal to the point at infinity. */
void static secp256k1_gej_set_infinity(secp256k1_gej_t *r);
/** Set a group element (jacobian) equal to the point with given X and Y coordinates. */
void static secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y);
/** Set a group element (jacobian) equal to another which is given in affine coordinates. */
void static secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a);
/** Get the X coordinate of a group element (jacobian). */
void static secp256k1_gej_get_x(secp256k1_fe_t *r, const secp256k1_gej_t *a);
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
void static secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a);
/** Check whether a group element is the point at infinity. */
int static secp256k1_gej_is_infinity(const secp256k1_gej_t *a);
/** Set r equal to the double of a. */
void static secp256k1_gej_double(secp256k1_gej_t *r, const secp256k1_gej_t *a);
/** Set r equal to the sum of a and b. */
void static secp256k1_gej_add(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b);
/** Set r equal to the sum of a and b (with b given in jacobian coordinates). This is more efficient
than secp256k1_gej_add. */
void static secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b);
/** Get a hex representation of a point. *rlen will be overwritten with the real length. */
void static secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a);
/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */
void static secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a);
/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (given that a is
not more than 256 bits). */
void static secp256k1_gej_split_exp(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a);
#endif

View File

@ -0,0 +1,309 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_ECDSA_IMPL_H_
#define _SECP256K1_ECDSA_IMPL_H_
#include "../num.h"
#include "../field.h"
#include "../group.h"
#include "../ecmult.h"
#include "../ecdsa.h"
void static secp256k1_ecdsa_sig_init(secp256k1_ecdsa_sig_t *r) {
secp256k1_num_init(&r->r);
secp256k1_num_init(&r->s);
}
void static secp256k1_ecdsa_sig_free(secp256k1_ecdsa_sig_t *r) {
secp256k1_num_free(&r->r);
secp256k1_num_free(&r->s);
}
int static secp256k1_ecdsa_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) {
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
secp256k1_fe_t x;
secp256k1_fe_set_b32(&x, pub+1);
secp256k1_ge_set_xo(elem, &x, pub[0] == 0x03);
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
secp256k1_fe_t x, y;
secp256k1_fe_set_b32(&x, pub+1);
secp256k1_fe_set_b32(&y, pub+33);
secp256k1_ge_set_xy(elem, &x, &y);
if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07))
return 0;
} else {
return 0;
}
return secp256k1_ge_is_valid(elem);
}
int static secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) {
if (sig[0] != 0x30) return 0;
int lenr = sig[3];
if (5+lenr >= size) return 0;
int lens = sig[lenr+5];
if (sig[1] != lenr+lens+4) return 0;
if (lenr+lens+6 > size) return 0;
if (sig[2] != 0x02) return 0;
if (lenr == 0) return 0;
if (sig[lenr+4] != 0x02) return 0;
if (lens == 0) return 0;
secp256k1_num_set_bin(&r->r, sig+4, lenr);
secp256k1_num_set_bin(&r->s, sig+6+lenr, lens);
return 1;
}
int static secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) {
int lenR = (secp256k1_num_bits(&a->r) + 7)/8;
if (lenR == 0 || secp256k1_num_get_bit(&a->r, lenR*8-1))
lenR++;
int lenS = (secp256k1_num_bits(&a->s) + 7)/8;
if (lenS == 0 || secp256k1_num_get_bit(&a->s, lenS*8-1))
lenS++;
if (*size < 6+lenS+lenR)
return 0;
*size = 6 + lenS + lenR;
sig[0] = 0x30;
sig[1] = 4 + lenS + lenR;
sig[2] = 0x02;
sig[3] = lenR;
secp256k1_num_get_bin(sig+4, lenR, &a->r);
sig[4+lenR] = 0x02;
sig[5+lenR] = lenS;
secp256k1_num_get_bin(sig+lenR+6, lenS, &a->s);
return 1;
}
int static secp256k1_ecdsa_sig_recompute(secp256k1_num_t *r2, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message) {
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
if (secp256k1_num_is_neg(&sig->r) || secp256k1_num_is_neg(&sig->s))
return 0;
if (secp256k1_num_is_zero(&sig->r) || secp256k1_num_is_zero(&sig->s))
return 0;
if (secp256k1_num_cmp(&sig->r, &c->order) >= 0 || secp256k1_num_cmp(&sig->s, &c->order) >= 0)
return 0;
int ret = 0;
secp256k1_num_t sn, u1, u2;
secp256k1_num_init(&sn);
secp256k1_num_init(&u1);
secp256k1_num_init(&u2);
secp256k1_num_mod_inverse(&sn, &sig->s, &c->order);
secp256k1_num_mod_mul(&u1, &sn, message, &c->order);
secp256k1_num_mod_mul(&u2, &sn, &sig->r, &c->order);
secp256k1_gej_t pubkeyj; secp256k1_gej_set_ge(&pubkeyj, pubkey);
secp256k1_gej_t pr; secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1);
if (!secp256k1_gej_is_infinity(&pr)) {
secp256k1_fe_t xr; secp256k1_gej_get_x(&xr, &pr);
secp256k1_fe_normalize(&xr);
unsigned char xrb[32]; secp256k1_fe_get_b32(xrb, &xr);
secp256k1_num_set_bin(r2, xrb, 32);
secp256k1_num_mod(r2, &c->order);
ret = 1;
}
secp256k1_num_free(&sn);
secp256k1_num_free(&u1);
secp256k1_num_free(&u2);
return ret;
}
int static secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid) {
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
if (secp256k1_num_is_neg(&sig->r) || secp256k1_num_is_neg(&sig->s))
return 0;
if (secp256k1_num_is_zero(&sig->r) || secp256k1_num_is_zero(&sig->s))
return 0;
if (secp256k1_num_cmp(&sig->r, &c->order) >= 0 || secp256k1_num_cmp(&sig->s, &c->order) >= 0)
return 0;
secp256k1_num_t rx;
secp256k1_num_init(&rx);
secp256k1_num_copy(&rx, &sig->r);
if (recid & 2) {
secp256k1_num_add(&rx, &rx, &c->order);
if (secp256k1_num_cmp(&rx, &secp256k1_fe_consts->p) >= 0)
return 0;
}
unsigned char brx[32];
secp256k1_num_get_bin(brx, 32, &rx);
secp256k1_num_free(&rx);
secp256k1_fe_t fx;
secp256k1_fe_set_b32(&fx, brx);
secp256k1_ge_t x;
secp256k1_ge_set_xo(&x, &fx, recid & 1);
if (!secp256k1_ge_is_valid(&x))
return 0;
secp256k1_gej_t xj;
secp256k1_gej_set_ge(&xj, &x);
secp256k1_num_t rn, u1, u2;
secp256k1_num_init(&rn);
secp256k1_num_init(&u1);
secp256k1_num_init(&u2);
secp256k1_num_mod_inverse(&rn, &sig->r, &c->order);
secp256k1_num_mod_mul(&u1, &rn, message, &c->order);
secp256k1_num_sub(&u1, &c->order, &u1);
secp256k1_num_mod_mul(&u2, &rn, &sig->s, &c->order);
secp256k1_gej_t qj;
secp256k1_ecmult(&qj, &xj, &u2, &u1);
if (secp256k1_gej_is_infinity(&qj))
return 0;
secp256k1_ge_set_gej(pubkey, &qj);
secp256k1_num_free(&rn);
secp256k1_num_free(&u1);
secp256k1_num_free(&u2);
return 1;
}
int static secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message) {
secp256k1_num_t r2;
secp256k1_num_init(&r2);
int ret = 0;
ret = secp256k1_ecdsa_sig_recompute(&r2, sig, pubkey, message) && secp256k1_num_cmp(&sig->r, &r2) == 0;
secp256k1_num_free(&r2);
return ret;
}
int static secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *seckey, const secp256k1_num_t *message, const secp256k1_num_t *nonce, int *recid) {
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
secp256k1_gej_t rp;
secp256k1_ecmult_gen(&rp, nonce);
secp256k1_ge_t r;
secp256k1_ge_set_gej(&r, &rp);
unsigned char b[32];
secp256k1_fe_normalize(&r.x);
secp256k1_fe_normalize(&r.y);
secp256k1_fe_get_b32(b, &r.x);
secp256k1_num_set_bin(&sig->r, b, 32);
if (recid)
*recid = (secp256k1_num_cmp(&sig->r, &c->order) >= 0 ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
secp256k1_num_mod(&sig->r, &c->order);
secp256k1_num_t n;
secp256k1_num_init(&n);
secp256k1_num_mod_mul(&n, &sig->r, seckey, &c->order);
secp256k1_num_add(&n, &n, message);
secp256k1_num_mod(&n, &c->order);
secp256k1_num_mod_inverse(&sig->s, nonce, &c->order);
secp256k1_num_mod_mul(&sig->s, &sig->s, &n, &c->order);
secp256k1_num_free(&n);
if (secp256k1_num_is_zero(&sig->s))
return 0;
if (secp256k1_num_cmp(&sig->s, &c->half_order) > 0) {
secp256k1_num_sub(&sig->s, &c->order, &sig->s);
if (recid)
*recid ^= 1;
}
return 1;
}
void static secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s) {
secp256k1_num_copy(&sig->r, r);
secp256k1_num_copy(&sig->s, s);
}
void static secp256k1_ecdsa_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed) {
secp256k1_fe_normalize(&elem->x);
secp256k1_fe_normalize(&elem->y);
secp256k1_fe_get_b32(&pub[1], &elem->x);
if (compressed) {
*size = 33;
pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);
} else {
*size = 65;
pub[0] = 0x04;
secp256k1_fe_get_b32(&pub[33], &elem->y);
}
}
int static secp256k1_ecdsa_privkey_parse(secp256k1_num_t *key, const unsigned char *privkey, int privkeylen) {
const unsigned char *end = privkey + privkeylen;
// sequence header
if (end < privkey+1 || *privkey != 0x30)
return 0;
privkey++;
// sequence length constructor
int lenb = 0;
if (end < privkey+1 || !(*privkey & 0x80))
return 0;
lenb = *privkey & ~0x80; privkey++;
if (lenb < 1 || lenb > 2)
return 0;
if (end < privkey+lenb)
return 0;
// sequence length
int len = 0;
len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
privkey += lenb;
if (end < privkey+len)
return 0;
// sequence element 0: version number (=1)
if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01)
return 0;
privkey += 3;
// sequence element 1: octet string, up to 32 bytes
if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1])
return 0;
secp256k1_num_set_bin(key, privkey+2, privkey[1]);
return 1;
}
int static secp256k1_ecdsa_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_num_t *key, int compressed) {
secp256k1_gej_t rp;
secp256k1_ecmult_gen(&rp, key);
secp256k1_ge_t r;
secp256k1_ge_set_gej(&r, &rp);
if (compressed) {
static const unsigned char begin[] = {
0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
};
static const unsigned char middle[] = {
0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
};
unsigned char *ptr = privkey;
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
secp256k1_num_get_bin(ptr, 32, key); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
int pubkeylen = 0;
secp256k1_ecdsa_pubkey_serialize(&r, ptr, &pubkeylen, 1); ptr += pubkeylen;
*privkeylen = ptr - privkey;
} else {
static const unsigned char begin[] = {
0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
};
static const unsigned char middle[] = {
0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,
0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,
0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
};
unsigned char *ptr = privkey;
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
secp256k1_num_get_bin(ptr, 32, key); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
int pubkeylen = 0;
secp256k1_ecdsa_pubkey_serialize(&r, ptr, &pubkeylen, 0); ptr += pubkeylen;
*privkeylen = ptr - privkey;
}
return 1;
}
#endif

View File

@ -0,0 +1,238 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_ECMULT_IMPL_H_
#define _SECP256K1_ECMULT_IMPL_H_
#include "../num.h"
#include "../group.h"
#include "../ecmult.h"
// optimal for 128-bit and 256-bit exponents.
#define WINDOW_A 5
// larger numbers may result in slightly better performance, at the cost of
// exponentially larger precomputed tables. WINDOW_G == 14 results in 640 KiB.
#define WINDOW_G 14
/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table.
* pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for
* 2^(w-2) entries.
*
* There are two versions of this function:
* - secp256k1_ecmult_precomp_wnaf_gej, which operates on group elements in jacobian notation,
* fast to precompute, but slower to use in later additions.
* - secp256k1_ecmult_precomp_wnaf_ge, which operates on group elements in affine notations,
* (much) slower to precompute, but a bit faster to use in later additions.
* To compute a*P + b*G, we use the jacobian version for P, and the affine version for G, as
* G is constant, so it only needs to be done once in advance.
*/
void static secp256k1_ecmult_table_precomp_gej(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) {
pre[0] = *a;
secp256k1_gej_t d; secp256k1_gej_double(&d, &pre[0]);
for (int i=1; i<(1 << (w-2)); i++)
secp256k1_gej_add(&pre[i], &d, &pre[i-1]);
}
void static secp256k1_ecmult_table_precomp_ge(secp256k1_ge_t *pre, const secp256k1_ge_t *a, int w) {
pre[0] = *a;
secp256k1_gej_t x; secp256k1_gej_set_ge(&x, a);
secp256k1_gej_t d; secp256k1_gej_double(&d, &x);
for (int i=1; i<(1 << (w-2)); i++) {
secp256k1_gej_add_ge(&x, &d, &pre[i-1]);
secp256k1_ge_set_gej(&pre[i], &x);
}
}
/** The number of entries a table with precomputed multiples needs to have. */
#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
/** The following two macro retrieves a particular odd multiple from a table
* of precomputed multiples. */
#define ECMULT_TABLE_GET(r,pre,n,w,neg) do { \
assert(((n) & 1) == 1); \
assert((n) >= -((1 << ((w)-1)) - 1)); \
assert((n) <= ((1 << ((w)-1)) - 1)); \
if ((n) > 0) \
*(r) = (pre)[((n)-1)/2]; \
else \
(neg)((r), &(pre)[(-(n)-1)/2]); \
} while(0)
#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_gej_neg)
#define ECMULT_TABLE_GET_GE(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_ge_neg)
typedef struct {
secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of the generator
secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of 2^128*generator
secp256k1_ge_t prec[64][16]; // prec[j][i] = 16^j * (i+1) * G
secp256k1_ge_t fin; // -(sum(prec[j][0], j=0..63))
} secp256k1_ecmult_consts_t;
static const secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL;
static void secp256k1_ecmult_start(void) {
if (secp256k1_ecmult_consts != NULL)
return;
secp256k1_ecmult_consts_t *ret = (secp256k1_ecmult_consts_t*)malloc(sizeof(secp256k1_ecmult_consts_t));
secp256k1_ecmult_consts = ret;
// get the generator
const secp256k1_ge_t *g = &secp256k1_ge_consts->g;
// calculate 2^128*generator
secp256k1_gej_t g_128j; secp256k1_gej_set_ge(&g_128j, g);
for (int i=0; i<128; i++)
secp256k1_gej_double(&g_128j, &g_128j);
secp256k1_ge_t g_128; secp256k1_ge_set_gej(&g_128, &g_128j);
// precompute the tables with odd multiples
secp256k1_ecmult_table_precomp_ge(ret->pre_g, g, WINDOW_G);
secp256k1_ecmult_table_precomp_ge(ret->pre_g_128, &g_128, WINDOW_G);
// compute prec and fin
secp256k1_gej_t gg; secp256k1_gej_set_ge(&gg, g);
secp256k1_ge_t ad = *g;
secp256k1_gej_t fn; secp256k1_gej_set_infinity(&fn);
for (int j=0; j<64; j++) {
secp256k1_ge_set_gej(&ret->prec[j][0], &gg);
secp256k1_gej_add(&fn, &fn, &gg);
for (int i=1; i<16; i++) {
secp256k1_gej_add_ge(&gg, &gg, &ad);
secp256k1_ge_set_gej(&ret->prec[j][i], &gg);
}
ad = ret->prec[j][15];
}
secp256k1_ge_set_gej(&ret->fin, &fn);
secp256k1_ge_neg(&ret->fin, &ret->fin);
}
static void secp256k1_ecmult_stop(void) {
if (secp256k1_ecmult_consts == NULL)
return;
secp256k1_ecmult_consts_t *c = (secp256k1_ecmult_consts_t*)secp256k1_ecmult_consts;
free(c);
secp256k1_ecmult_consts = NULL;
}
/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),
* with the following guarantees:
* - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1)
* - two non-zero entries in wnaf are separated by at least w-1 zeroes.
* - the index of the highest non-zero entry in wnaf (=return value-1) is at most bits, where
* bits is the number of bits necessary to represent the absolute value of the input.
*/
static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_num_t *a, int w) {
int ret = 0;
int zeroes = 0;
secp256k1_num_t x;
secp256k1_num_init(&x);
secp256k1_num_copy(&x, a);
int sign = 1;
if (secp256k1_num_is_neg(&x)) {
sign = -1;
secp256k1_num_negate(&x);
}
while (!secp256k1_num_is_zero(&x)) {
while (!secp256k1_num_is_odd(&x)) {
zeroes++;
secp256k1_num_shift(&x, 1);
}
int word = secp256k1_num_shift(&x, w);
while (zeroes) {
wnaf[ret++] = 0;
zeroes--;
}
if (word & (1 << (w-1))) {
secp256k1_num_inc(&x);
wnaf[ret++] = sign * (word - (1 << w));
} else {
wnaf[ret++] = sign * word;
}
zeroes = w-1;
}
secp256k1_num_free(&x);
return ret;
}
void static secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *gn) {
secp256k1_num_t n;
secp256k1_num_init(&n);
secp256k1_num_copy(&n, gn);
const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
secp256k1_gej_set_ge(r, &c->prec[0][secp256k1_num_shift(&n, 4)]);
for (int j=1; j<64; j++)
secp256k1_gej_add_ge(r, r, &c->prec[j][secp256k1_num_shift(&n, 4)]);
secp256k1_num_free(&n);
secp256k1_gej_add_ge(r, r, &c->fin);
}
void static secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng) {
const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
secp256k1_num_t na_1, na_lam;
secp256k1_num_t ng_1, ng_128;
secp256k1_num_init(&na_1);
secp256k1_num_init(&na_lam);
secp256k1_num_init(&ng_1);
secp256k1_num_init(&ng_128);
// split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit)
secp256k1_gej_split_exp(&na_1, &na_lam, na);
// split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit)
secp256k1_num_split(&ng_1, &ng_128, ng, 128);
// build wnaf representation for na_1, na_lam, ng_1, ng_128
int wnaf_na_1[129]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A);
int wnaf_na_lam[129]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
int wnaf_ng_1[129]; int bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G);
int wnaf_ng_128[129]; int bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G);
// calculate a_lam = a*lambda
secp256k1_gej_t a_lam; secp256k1_gej_mul_lambda(&a_lam, a);
// calculate odd multiples of a and a_lam
secp256k1_gej_t pre_a_1[ECMULT_TABLE_SIZE(WINDOW_A)], pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_ecmult_table_precomp_gej(pre_a_1, a, WINDOW_A);
secp256k1_ecmult_table_precomp_gej(pre_a_lam, &a_lam, WINDOW_A);
int bits = bits_na_1;
if (bits_na_lam > bits) bits = bits_na_lam;
if (bits_ng_1 > bits) bits = bits_ng_1;
if (bits_ng_128 > bits) bits = bits_ng_128;
secp256k1_gej_set_infinity(r);
secp256k1_gej_t tmpj;
secp256k1_ge_t tmpa;
for (int i=bits-1; i>=0; i--) {
secp256k1_gej_double(r, r);
int n;
if (i < bits_na_1 && (n = wnaf_na_1[i])) {
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_1, n, WINDOW_A);
secp256k1_gej_add(r, r, &tmpj);
}
if (i < bits_na_lam && (n = wnaf_na_lam[i])) {
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A);
secp256k1_gej_add(r, r, &tmpj);
}
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G);
secp256k1_gej_add_ge(r, r, &tmpa);
}
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g_128, n, WINDOW_G);
secp256k1_gej_add_ge(r, r, &tmpa);
}
}
secp256k1_num_free(&na_1);
secp256k1_num_free(&na_lam);
secp256k1_num_free(&ng_1);
secp256k1_num_free(&ng_128);
}
#endif

View File

@ -0,0 +1,175 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_IMPL_H_
#define _SECP256K1_FIELD_IMPL_H_
#if defined(USE_FIELD_GMP)
#include "field_gmp.h"
#elif defined(USE_FIELD_10X26)
#include "field_10x26.h"
#elif defined(USE_FIELD_5X52)
#include "field_5x52.h"
#elif defined(USE_FIELD_5X64)
#include "field_5x64.h"
#else
#error "Please select field implementation"
#endif
void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a) {
if (*rlen < 65) {
*rlen = 65;
return;
}
*rlen = 65;
unsigned char tmp[32];
secp256k1_fe_t b = *a;
secp256k1_fe_normalize(&b);
secp256k1_fe_get_b32(tmp, &b);
for (int i=0; i<32; i++) {
static const char *c = "0123456789ABCDEF";
r[2*i] = c[(tmp[i] >> 4) & 0xF];
r[2*i+1] = c[(tmp[i]) & 0xF];
}
r[64] = 0x00;
}
void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) {
unsigned char tmp[32] = {};
static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,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,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0};
for (int i=0; i<32; i++) {
if (alen > i*2)
tmp[32 - alen/2 + i] = (cvt[(unsigned char)a[2*i]] << 4) + cvt[(unsigned char)a[2*i+1]];
}
secp256k1_fe_set_b32(r, tmp);
}
void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
// calculate a^p, with p={15,780,1022,1023}
secp256k1_fe_t a2; secp256k1_fe_sqr(&a2, a);
secp256k1_fe_t a3; secp256k1_fe_mul(&a3, &a2, a);
secp256k1_fe_t a6; secp256k1_fe_sqr(&a6, &a3);
secp256k1_fe_t a12; secp256k1_fe_sqr(&a12, &a6);
secp256k1_fe_t a15; secp256k1_fe_mul(&a15, &a12, &a3);
secp256k1_fe_t a30; secp256k1_fe_sqr(&a30, &a15);
secp256k1_fe_t a60; secp256k1_fe_sqr(&a60, &a30);
secp256k1_fe_t a120; secp256k1_fe_sqr(&a120, &a60);
secp256k1_fe_t a240; secp256k1_fe_sqr(&a240, &a120);
secp256k1_fe_t a255; secp256k1_fe_mul(&a255, &a240, &a15);
secp256k1_fe_t a510; secp256k1_fe_sqr(&a510, &a255);
secp256k1_fe_t a750; secp256k1_fe_mul(&a750, &a510, &a240);
secp256k1_fe_t a780; secp256k1_fe_mul(&a780, &a750, &a30);
secp256k1_fe_t a1020; secp256k1_fe_sqr(&a1020, &a510);
secp256k1_fe_t a1022; secp256k1_fe_mul(&a1022, &a1020, &a2);
secp256k1_fe_t a1023; secp256k1_fe_mul(&a1023, &a1022, a);
secp256k1_fe_t x = a15;
for (int i=0; i<21; i++) {
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1023);
}
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1022);
for (int i=0; i<2; i++) {
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1023);
}
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(r, &x, &a780);
}
void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
// calculate a^p, with p={45,63,1019,1023}
secp256k1_fe_t a2; secp256k1_fe_sqr(&a2, a);
secp256k1_fe_t a3; secp256k1_fe_mul(&a3, &a2, a);
secp256k1_fe_t a4; secp256k1_fe_sqr(&a4, &a2);
secp256k1_fe_t a5; secp256k1_fe_mul(&a5, &a4, a);
secp256k1_fe_t a10; secp256k1_fe_sqr(&a10, &a5);
secp256k1_fe_t a11; secp256k1_fe_mul(&a11, &a10, a);
secp256k1_fe_t a21; secp256k1_fe_mul(&a21, &a11, &a10);
secp256k1_fe_t a42; secp256k1_fe_sqr(&a42, &a21);
secp256k1_fe_t a45; secp256k1_fe_mul(&a45, &a42, &a3);
secp256k1_fe_t a63; secp256k1_fe_mul(&a63, &a42, &a21);
secp256k1_fe_t a126; secp256k1_fe_sqr(&a126, &a63);
secp256k1_fe_t a252; secp256k1_fe_sqr(&a252, &a126);
secp256k1_fe_t a504; secp256k1_fe_sqr(&a504, &a252);
secp256k1_fe_t a1008; secp256k1_fe_sqr(&a1008, &a504);
secp256k1_fe_t a1019; secp256k1_fe_mul(&a1019, &a1008, &a11);
secp256k1_fe_t a1023; secp256k1_fe_mul(&a1023, &a1019, &a4);
secp256k1_fe_t x = a63;
for (int i=0; i<21; i++) {
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1023);
}
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1019);
for (int i=0; i<2; i++) {
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1023);
}
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(r, &x, &a45);
}
void static secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#if defined(USE_FIELD_INV_BUILTIN)
secp256k1_fe_inv(r, a);
#elif defined(USE_FIELD_INV_NUM)
unsigned char b[32];
secp256k1_fe_t c = *a;
secp256k1_fe_normalize(&c);
secp256k1_fe_get_b32(b, &c);
secp256k1_num_t n;
secp256k1_num_init(&n);
secp256k1_num_set_bin(&n, b, 32);
secp256k1_num_mod_inverse(&n, &n, &secp256k1_fe_consts->p);
secp256k1_num_get_bin(b, 32, &n);
secp256k1_num_free(&n);
secp256k1_fe_set_b32(r, b);
#else
#error "Please select field inverse implementation"
#endif
}
void static secp256k1_fe_start(void) {
static const unsigned char secp256k1_fe_consts_p[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
};
if (secp256k1_fe_consts == NULL) {
secp256k1_fe_inner_start();
secp256k1_fe_consts_t *ret = (secp256k1_fe_consts_t*)malloc(sizeof(secp256k1_fe_consts_t));
secp256k1_num_init(&ret->p);
secp256k1_num_set_bin(&ret->p, secp256k1_fe_consts_p, sizeof(secp256k1_fe_consts_p));
secp256k1_fe_consts = ret;
}
}
void static secp256k1_fe_stop(void) {
if (secp256k1_fe_consts != NULL) {
secp256k1_fe_consts_t *c = (secp256k1_fe_consts_t*)secp256k1_fe_consts;
secp256k1_num_free(&c->p);
free((void*)c);
secp256k1_fe_consts = NULL;
secp256k1_fe_inner_stop();
}
}
#endif

View File

@ -0,0 +1,487 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
#define _SECP256K1_FIELD_REPR_IMPL_H_
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "../num.h"
#include "../field.h"
void static secp256k1_fe_inner_start(void) {}
void static secp256k1_fe_inner_stop(void) {}
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
// fog("normalize in: ", r);
uint32_t c;
c = r->n[0];
uint32_t t0 = c & 0x3FFFFFFUL;
c = (c >> 26) + r->n[1];
uint32_t t1 = c & 0x3FFFFFFUL;
c = (c >> 26) + r->n[2];
uint32_t t2 = c & 0x3FFFFFFUL;
c = (c >> 26) + r->n[3];
uint32_t t3 = c & 0x3FFFFFFUL;
c = (c >> 26) + r->n[4];
uint32_t t4 = c & 0x3FFFFFFUL;
c = (c >> 26) + r->n[5];
uint32_t t5 = c & 0x3FFFFFFUL;
c = (c >> 26) + r->n[6];
uint32_t t6 = c & 0x3FFFFFFUL;
c = (c >> 26) + r->n[7];
uint32_t t7 = c & 0x3FFFFFFUL;
c = (c >> 26) + r->n[8];
uint32_t t8 = c & 0x3FFFFFFUL;
c = (c >> 26) + r->n[9];
uint32_t t9 = c & 0x03FFFFFUL;
c >>= 22;
/* r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
fog(" tm1: ", r);
fprintf(stderr, "out c= %08lx\n", (unsigned long)c);*/
// The following code will not modify the t's if c is initially 0.
uint32_t d = c * 0x3D1UL + t0;
t0 = d & 0x3FFFFFFULL;
d = (d >> 26) + t1 + c*0x40;
t1 = d & 0x3FFFFFFULL;
d = (d >> 26) + t2;
t2 = d & 0x3FFFFFFULL;
d = (d >> 26) + t3;
t3 = d & 0x3FFFFFFULL;
d = (d >> 26) + t4;
t4 = d & 0x3FFFFFFULL;
d = (d >> 26) + t5;
t5 = d & 0x3FFFFFFULL;
d = (d >> 26) + t6;
t6 = d & 0x3FFFFFFULL;
d = (d >> 26) + t7;
t7 = d & 0x3FFFFFFULL;
d = (d >> 26) + t8;
t8 = d & 0x3FFFFFFULL;
d = (d >> 26) + t9;
t9 = d & 0x03FFFFFULL;
assert((d >> 22) == 0);
/* r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
fog(" tm2: ", r); */
// Subtract p if result >= p
uint64_t low = ((uint64_t)t1 << 26) | t0;
uint64_t mask = -(int64_t)((t9 < 0x03FFFFFUL) | (t8 < 0x3FFFFFFUL) | (t7 < 0x3FFFFFFUL) | (t6 < 0x3FFFFFFUL) | (t5 < 0x3FFFFFFUL) | (t4 < 0x3FFFFFFUL) | (t3 < 0x3FFFFFFUL) | (t2 < 0x3FFFFFFUL) | (low < 0xFFFFEFFFFFC2FULL));
t9 &= mask;
t8 &= mask;
t7 &= mask;
t6 &= mask;
t5 &= mask;
t4 &= mask;
t3 &= mask;
t2 &= mask;
low -= (~mask & 0xFFFFEFFFFFC2FULL);
// push internal variables back
r->n[0] = low & 0x3FFFFFFUL; r->n[1] = (low >> 26) & 0x3FFFFFFUL; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
/* fog(" out: ", r);*/
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
#endif
}
void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
#endif
}
// TODO: not constant time!
int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0 && a->n[4] == 0 && a->n[5] == 0 && a->n[6] == 0 && a->n[7] == 0 && a->n[8] == 0 && a->n[9] == 0);
}
int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
return a->n[0] & 1;
}
// TODO: not constant time!
int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
#ifdef VERIFY
assert(a->normalized);
assert(b->normalized);
#endif
return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3] && a->n[4] == b->n[4] &&
a->n[5] == b->n[5] && a->n[6] == b->n[6] && a->n[7] == b->n[7] && a->n[8] == b->n[8] && a->n[9] == b->n[9]);
}
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
for (int i=0; i<32; i++) {
for (int j=0; j<4; j++) {
int limb = (8*i+2*j)/26;
int shift = (8*i+2*j)%26;
r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
}
}
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
#endif
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
for (int i=0; i<32; i++) {
int c = 0;
for (int j=0; j<4; j++) {
int limb = (8*i+2*j)/26;
int shift = (8*i+2*j)%26;
c |= ((a->n[limb] >> shift) & 0x3) << (2 * j);
}
r[31-i] = c;
}
}
void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
#ifdef VERIFY
assert(a->magnitude <= m);
r->magnitude = m + 1;
r->normalized = 0;
#endif
r->n[0] = 0x3FFFC2FUL * (m + 1) - a->n[0];
r->n[1] = 0x3FFFFBFUL * (m + 1) - a->n[1];
r->n[2] = 0x3FFFFFFUL * (m + 1) - a->n[2];
r->n[3] = 0x3FFFFFFUL * (m + 1) - a->n[3];
r->n[4] = 0x3FFFFFFUL * (m + 1) - a->n[4];
r->n[5] = 0x3FFFFFFUL * (m + 1) - a->n[5];
r->n[6] = 0x3FFFFFFUL * (m + 1) - a->n[6];
r->n[7] = 0x3FFFFFFUL * (m + 1) - a->n[7];
r->n[8] = 0x3FFFFFFUL * (m + 1) - a->n[8];
r->n[9] = 0x03FFFFFUL * (m + 1) - a->n[9];
}
void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
#ifdef VERIFY
r->magnitude *= a;
r->normalized = 0;
#endif
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
r->n[3] *= a;
r->n[4] *= a;
r->n[5] *= a;
r->n[6] *= a;
r->n[7] *= a;
r->n[8] *= a;
r->n[9] *= a;
}
void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
r->magnitude += a->magnitude;
r->normalized = 0;
#endif
r->n[0] += a->n[0];
r->n[1] += a->n[1];
r->n[2] += a->n[2];
r->n[3] += a->n[3];
r->n[4] += a->n[4];
r->n[5] += a->n[5];
r->n[6] += a->n[6];
r->n[7] += a->n[7];
r->n[8] += a->n[8];
r->n[9] += a->n[9];
}
void static inline secp256k1_fe_mul_inner(const uint32_t *a, const uint32_t *b, uint32_t *r) {
uint64_t c = (uint64_t)a[0] * b[0];
uint32_t t0 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[0] * b[1] +
(uint64_t)a[1] * b[0];
uint32_t t1 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[0] * b[2] +
(uint64_t)a[1] * b[1] +
(uint64_t)a[2] * b[0];
uint32_t t2 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[0] * b[3] +
(uint64_t)a[1] * b[2] +
(uint64_t)a[2] * b[1] +
(uint64_t)a[3] * b[0];
uint32_t t3 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[0] * b[4] +
(uint64_t)a[1] * b[3] +
(uint64_t)a[2] * b[2] +
(uint64_t)a[3] * b[1] +
(uint64_t)a[4] * b[0];
uint32_t t4 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[0] * b[5] +
(uint64_t)a[1] * b[4] +
(uint64_t)a[2] * b[3] +
(uint64_t)a[3] * b[2] +
(uint64_t)a[4] * b[1] +
(uint64_t)a[5] * b[0];
uint32_t t5 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[0] * b[6] +
(uint64_t)a[1] * b[5] +
(uint64_t)a[2] * b[4] +
(uint64_t)a[3] * b[3] +
(uint64_t)a[4] * b[2] +
(uint64_t)a[5] * b[1] +
(uint64_t)a[6] * b[0];
uint32_t t6 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[0] * b[7] +
(uint64_t)a[1] * b[6] +
(uint64_t)a[2] * b[5] +
(uint64_t)a[3] * b[4] +
(uint64_t)a[4] * b[3] +
(uint64_t)a[5] * b[2] +
(uint64_t)a[6] * b[1] +
(uint64_t)a[7] * b[0];
uint32_t t7 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[0] * b[8] +
(uint64_t)a[1] * b[7] +
(uint64_t)a[2] * b[6] +
(uint64_t)a[3] * b[5] +
(uint64_t)a[4] * b[4] +
(uint64_t)a[5] * b[3] +
(uint64_t)a[6] * b[2] +
(uint64_t)a[7] * b[1] +
(uint64_t)a[8] * b[0];
uint32_t t8 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[0] * b[9] +
(uint64_t)a[1] * b[8] +
(uint64_t)a[2] * b[7] +
(uint64_t)a[3] * b[6] +
(uint64_t)a[4] * b[5] +
(uint64_t)a[5] * b[4] +
(uint64_t)a[6] * b[3] +
(uint64_t)a[7] * b[2] +
(uint64_t)a[8] * b[1] +
(uint64_t)a[9] * b[0];
uint32_t t9 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[1] * b[9] +
(uint64_t)a[2] * b[8] +
(uint64_t)a[3] * b[7] +
(uint64_t)a[4] * b[6] +
(uint64_t)a[5] * b[5] +
(uint64_t)a[6] * b[4] +
(uint64_t)a[7] * b[3] +
(uint64_t)a[8] * b[2] +
(uint64_t)a[9] * b[1];
uint32_t t10 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[2] * b[9] +
(uint64_t)a[3] * b[8] +
(uint64_t)a[4] * b[7] +
(uint64_t)a[5] * b[6] +
(uint64_t)a[6] * b[5] +
(uint64_t)a[7] * b[4] +
(uint64_t)a[8] * b[3] +
(uint64_t)a[9] * b[2];
uint32_t t11 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[3] * b[9] +
(uint64_t)a[4] * b[8] +
(uint64_t)a[5] * b[7] +
(uint64_t)a[6] * b[6] +
(uint64_t)a[7] * b[5] +
(uint64_t)a[8] * b[4] +
(uint64_t)a[9] * b[3];
uint32_t t12 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[4] * b[9] +
(uint64_t)a[5] * b[8] +
(uint64_t)a[6] * b[7] +
(uint64_t)a[7] * b[6] +
(uint64_t)a[8] * b[5] +
(uint64_t)a[9] * b[4];
uint32_t t13 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[5] * b[9] +
(uint64_t)a[6] * b[8] +
(uint64_t)a[7] * b[7] +
(uint64_t)a[8] * b[6] +
(uint64_t)a[9] * b[5];
uint32_t t14 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[6] * b[9] +
(uint64_t)a[7] * b[8] +
(uint64_t)a[8] * b[7] +
(uint64_t)a[9] * b[6];
uint32_t t15 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[7] * b[9] +
(uint64_t)a[8] * b[8] +
(uint64_t)a[9] * b[7];
uint32_t t16 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[8] * b[9] +
(uint64_t)a[9] * b[8];
uint32_t t17 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[9] * b[9];
uint32_t t18 = c & 0x3FFFFFFUL; c = c >> 26;
uint32_t t19 = c;
c = t0 + (uint64_t)t10 * 0x3D10UL;
t0 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t1 + (uint64_t)t10*0x400UL + (uint64_t)t11 * 0x3D10UL;
t1 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t2 + (uint64_t)t11*0x400UL + (uint64_t)t12 * 0x3D10UL;
t2 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t3 + (uint64_t)t12*0x400UL + (uint64_t)t13 * 0x3D10UL;
r[3] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t4 + (uint64_t)t13*0x400UL + (uint64_t)t14 * 0x3D10UL;
r[4] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t5 + (uint64_t)t14*0x400UL + (uint64_t)t15 * 0x3D10UL;
r[5] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t6 + (uint64_t)t15*0x400UL + (uint64_t)t16 * 0x3D10UL;
r[6] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t7 + (uint64_t)t16*0x400UL + (uint64_t)t17 * 0x3D10UL;
r[7] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t8 + (uint64_t)t17*0x400UL + (uint64_t)t18 * 0x3D10UL;
r[8] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t9 + (uint64_t)t18*0x400UL + (uint64_t)t19 * 0x1000003D10ULL;
r[9] = c & 0x03FFFFFUL; c = c >> 22;
uint64_t d = t0 + c * 0x3D1UL;
r[0] = d & 0x3FFFFFFUL; d = d >> 26;
d = d + t1 + c*0x40;
r[1] = d & 0x3FFFFFFUL; d = d >> 26;
r[2] = t2 + d;
}
void static inline secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t *r) {
uint64_t c = (uint64_t)a[0] * a[0];
uint32_t t0 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[0]*2) * a[1];
uint32_t t1 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[0]*2) * a[2] +
(uint64_t)a[1] * a[1];
uint32_t t2 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[0]*2) * a[3] +
(uint64_t)(a[1]*2) * a[2];
uint32_t t3 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[0]*2) * a[4] +
(uint64_t)(a[1]*2) * a[3] +
(uint64_t)a[2] * a[2];
uint32_t t4 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[0]*2) * a[5] +
(uint64_t)(a[1]*2) * a[4] +
(uint64_t)(a[2]*2) * a[3];
uint32_t t5 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[0]*2) * a[6] +
(uint64_t)(a[1]*2) * a[5] +
(uint64_t)(a[2]*2) * a[4] +
(uint64_t)a[3] * a[3];
uint32_t t6 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[0]*2) * a[7] +
(uint64_t)(a[1]*2) * a[6] +
(uint64_t)(a[2]*2) * a[5] +
(uint64_t)(a[3]*2) * a[4];
uint32_t t7 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[0]*2) * a[8] +
(uint64_t)(a[1]*2) * a[7] +
(uint64_t)(a[2]*2) * a[6] +
(uint64_t)(a[3]*2) * a[5] +
(uint64_t)a[4] * a[4];
uint32_t t8 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[0]*2) * a[9] +
(uint64_t)(a[1]*2) * a[8] +
(uint64_t)(a[2]*2) * a[7] +
(uint64_t)(a[3]*2) * a[6] +
(uint64_t)(a[4]*2) * a[5];
uint32_t t9 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[1]*2) * a[9] +
(uint64_t)(a[2]*2) * a[8] +
(uint64_t)(a[3]*2) * a[7] +
(uint64_t)(a[4]*2) * a[6] +
(uint64_t)a[5] * a[5];
uint32_t t10 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[2]*2) * a[9] +
(uint64_t)(a[3]*2) * a[8] +
(uint64_t)(a[4]*2) * a[7] +
(uint64_t)(a[5]*2) * a[6];
uint32_t t11 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[3]*2) * a[9] +
(uint64_t)(a[4]*2) * a[8] +
(uint64_t)(a[5]*2) * a[7] +
(uint64_t)a[6] * a[6];
uint32_t t12 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[4]*2) * a[9] +
(uint64_t)(a[5]*2) * a[8] +
(uint64_t)(a[6]*2) * a[7];
uint32_t t13 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[5]*2) * a[9] +
(uint64_t)(a[6]*2) * a[8] +
(uint64_t)a[7] * a[7];
uint32_t t14 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[6]*2) * a[9] +
(uint64_t)(a[7]*2) * a[8];
uint32_t t15 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[7]*2) * a[9] +
(uint64_t)a[8] * a[8];
uint32_t t16 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)(a[8]*2) * a[9];
uint32_t t17 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + (uint64_t)a[9] * a[9];
uint32_t t18 = c & 0x3FFFFFFUL; c = c >> 26;
uint32_t t19 = c;
c = t0 + (uint64_t)t10 * 0x3D10UL;
t0 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t1 + (uint64_t)t10*0x400UL + (uint64_t)t11 * 0x3D10UL;
t1 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t2 + (uint64_t)t11*0x400UL + (uint64_t)t12 * 0x3D10UL;
t2 = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t3 + (uint64_t)t12*0x400UL + (uint64_t)t13 * 0x3D10UL;
r[3] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t4 + (uint64_t)t13*0x400UL + (uint64_t)t14 * 0x3D10UL;
r[4] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t5 + (uint64_t)t14*0x400UL + (uint64_t)t15 * 0x3D10UL;
r[5] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t6 + (uint64_t)t15*0x400UL + (uint64_t)t16 * 0x3D10UL;
r[6] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t7 + (uint64_t)t16*0x400UL + (uint64_t)t17 * 0x3D10UL;
r[7] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t8 + (uint64_t)t17*0x400UL + (uint64_t)t18 * 0x3D10UL;
r[8] = c & 0x3FFFFFFUL; c = c >> 26;
c = c + t9 + (uint64_t)t18*0x400UL + (uint64_t)t19 * 0x1000003D10ULL;
r[9] = c & 0x03FFFFFUL; c = c >> 22;
uint64_t d = t0 + c * 0x3D1UL;
r[0] = d & 0x3FFFFFFUL; d = d >> 26;
d = d + t1 + c*0x40;
r[1] = d & 0x3FFFFFFUL; d = d >> 26;
r[2] = t2 + d;
}
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
#ifdef VERIFY
assert(a->magnitude <= 8);
assert(b->magnitude <= 8);
r->magnitude = 1;
r->normalized = 0;
#endif
secp256k1_fe_mul_inner(a->n, b->n, r->n);
}
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->magnitude <= 8);
r->magnitude = 1;
r->normalized = 0;
#endif
secp256k1_fe_sqr_inner(a->n, r->n);
}
#endif

View File

@ -0,0 +1,196 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
#define _SECP256K1_FIELD_REPR_IMPL_H_
#include <assert.h>
#include <string.h>
#include "../num.h"
#include "../field.h"
#if defined(USE_FIELD_5X52_ASM)
#include "field_5x52_asm.h"
#elif defined(USE_FIELD_5X52_INT128)
#include "field_5x52_int128.h"
#else
#error "Please select field_5x52 implementation"
#endif
/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
* represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular,
* each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element
* is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations
* accept any input with magnitude at most M, and have different rules for propagating magnitude to their
* output.
*/
void static secp256k1_fe_inner_start(void) {}
void static secp256k1_fe_inner_stop(void) {}
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
uint64_t c;
c = r->n[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + r->n[1];
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + r->n[2];
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + r->n[3];
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + r->n[4];
uint64_t t4 = c & 0x0FFFFFFFFFFFFULL;
c >>= 48;
// The following code will not modify the t's if c is initially 0.
c = c * 0x1000003D1ULL + t0;
t0 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + t1;
t1 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + t2;
t2 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + t3;
t3 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + t4;
t4 = c & 0x0FFFFFFFFFFFFULL;
assert((c >> 48) == 0);
// Subtract p if result >= p
uint64_t mask = -(int64_t)((t4 < 0xFFFFFFFFFFFFULL) | (t3 < 0xFFFFFFFFFFFFFULL) | (t2 < 0xFFFFFFFFFFFFFULL) | (t1 < 0xFFFFFFFFFFFFFULL) | (t0 < 0xFFFFEFFFFFC2FULL));
t4 &= mask;
t3 &= mask;
t2 &= mask;
t1 &= mask;
t0 -= (~mask & 0xFFFFEFFFFFC2FULL);
// push internal variables back
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
#endif
}
void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
#endif
}
// TODO: not constant time!
int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0 && a->n[4] == 0);
}
int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
return a->n[0] & 1;
}
// TODO: not constant time!
int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
#ifdef VERIFY
assert(a->normalized);
assert(b->normalized);
#endif
return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3] && a->n[4] == b->n[4]);
}
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
for (int i=0; i<32; i++) {
for (int j=0; j<2; j++) {
int limb = (8*i+4*j)/52;
int shift = (8*i+4*j)%52;
r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
}
}
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
#endif
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
for (int i=0; i<32; i++) {
int c = 0;
for (int j=0; j<2; j++) {
int limb = (8*i+4*j)/52;
int shift = (8*i+4*j)%52;
c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
}
r[31-i] = c;
}
}
void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
#ifdef VERIFY
assert(a->magnitude <= m);
r->magnitude = m + 1;
r->normalized = 0;
#endif
r->n[0] = 0xFFFFEFFFFFC2FULL * (m + 1) - a->n[0];
r->n[1] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[1];
r->n[2] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[2];
r->n[3] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[3];
r->n[4] = 0x0FFFFFFFFFFFFULL * (m + 1) - a->n[4];
}
void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
#ifdef VERIFY
r->magnitude *= a;
r->normalized = 0;
#endif
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
r->n[3] *= a;
r->n[4] *= a;
}
void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
r->magnitude += a->magnitude;
r->normalized = 0;
#endif
r->n[0] += a->n[0];
r->n[1] += a->n[1];
r->n[2] += a->n[2];
r->n[3] += a->n[3];
r->n[4] += a->n[4];
}
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
#ifdef VERIFY
assert(a->magnitude <= 8);
assert(b->magnitude <= 8);
r->magnitude = 1;
r->normalized = 0;
#endif
secp256k1_fe_mul_inner(a->n, b->n, r->n);
}
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->magnitude <= 8);
r->magnitude = 1;
r->normalized = 0;
#endif
secp256k1_fe_sqr_inner(a->n, r->n);
}
#endif

View File

@ -0,0 +1,11 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
void __attribute__ ((sysv_abi)) secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r);
void __attribute__ ((sysv_abi)) secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r);
#endif

View File

@ -0,0 +1,105 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
#include <stdint.h>
void static inline secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r) {
__int128 c = (__int128)a[0] * b[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0
c = c + (__int128)a[0] * b[1] +
(__int128)a[1] * b[0];
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF
c = c + (__int128)a[0] * b[2] +
(__int128)a[1] * b[1] +
(__int128)a[2] * b[0];
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0
c = c + (__int128)a[0] * b[3] +
(__int128)a[1] * b[2] +
(__int128)a[2] * b[1] +
(__int128)a[3] * b[0];
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280
c = c + (__int128)a[0] * b[4] +
(__int128)a[1] * b[3] +
(__int128)a[2] * b[2] +
(__int128)a[3] * b[1] +
(__int128)a[4] * b[0];
uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E
c = c + (__int128)a[1] * b[4] +
(__int128)a[2] * b[3] +
(__int128)a[3] * b[2] +
(__int128)a[4] * b[1];
uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE
c = c + (__int128)a[2] * b[4] +
(__int128)a[3] * b[3] +
(__int128)a[4] * b[2];
uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE
c = c + (__int128)a[3] * b[4] +
(__int128)a[4] * b[3];
uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE
c = c + (__int128)a[4] * b[4];
uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E
uint64_t t9 = c;
c = t0 + (__int128)t5 * 0x1000003D10ULL;
t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t1 + (__int128)t6 * 0x1000003D10ULL;
t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t2 + (__int128)t7 * 0x1000003D10ULL;
r[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t3 + (__int128)t8 * 0x1000003D10ULL;
r[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t4 + (__int128)t9 * 0x1000003D10ULL;
r[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
c = t0 + (__int128)c * 0x1000003D1ULL;
r[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
r[1] = t1 + c;
}
void static inline secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r) {
__int128 c = (__int128)a[0] * a[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0
c = c + (__int128)(a[0]*2) * a[1];
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF
c = c + (__int128)(a[0]*2) * a[2] +
(__int128)a[1] * a[1];
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0
c = c + (__int128)(a[0]*2) * a[3] +
(__int128)(a[1]*2) * a[2];
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280
c = c + (__int128)(a[0]*2) * a[4] +
(__int128)(a[1]*2) * a[3] +
(__int128)a[2] * a[2];
uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E
c = c + (__int128)(a[1]*2) * a[4] +
(__int128)(a[2]*2) * a[3];
uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE
c = c + (__int128)(a[2]*2) * a[4] +
(__int128)a[3] * a[3];
uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE
c = c + (__int128)(a[3]*2) * a[4];
uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE
c = c + (__int128)a[4] * a[4];
uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E
uint64_t t9 = c;
c = t0 + (__int128)t5 * 0x1000003D10ULL;
t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t1 + (__int128)t6 * 0x1000003D10ULL;
t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t2 + (__int128)t7 * 0x1000003D10ULL;
r[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t3 + (__int128)t8 * 0x1000003D10ULL;
r[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t4 + (__int128)t9 * 0x1000003D10ULL;
r[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
c = t0 + (__int128)c * 0x1000003D1ULL;
r[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
r[1] = t1 + c;
}
#endif

View File

@ -0,0 +1,371 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
#define _SECP256K1_FIELD_REPR_IMPL_H_
#include <assert.h>
#include <string.h>
#include "../num.h"
#include "../field.h"
#include <stdio.h>
#include "field_5x64_asm.h"
/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
* represented as 4 uint64_t's in base 2^64, and one overflow uint64_t.
*/
#define FULL_LIMB (0xFFFFFFFFFFFFFFFFULL)
#define LAST_LIMB (0xFFFFFFFEFFFFFC2FULL)
#define COMP_LIMB (0x00000001000003D1ULL)
void static secp256k1_fe_inner_start(void) {}
void static secp256k1_fe_inner_stop(void) {}
void static secp256k1_fe_reduce(secp256k1_fe_t *r) {
unsigned __int128 c = (unsigned __int128)r->n[4] * COMP_LIMB + r->n[0];
uint64_t n0 = c;
c = (c >> 64) + r->n[1];
uint64_t n1 = c;
c = (c >> 64) + r->n[2];
r->n[2] = c;
c = (c >> 64) + r->n[3];
r->n[3] = c;
c = (c >> 64) * COMP_LIMB + n0;
r->n[0] = c;
r->n[1] = n1 + (c >> 64);
assert(r->n[1] >= n1);
r->n[4] = 0;
#ifdef VERIFY
r->reduced = 1;
#endif
}
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
secp256k1_fe_reduce(r);
// Subtract p if result >= p
uint64_t mask = -(int64_t)((r->n[0] < LAST_LIMB) | (r->n[1] != ~0ULL) | (r->n[2] != ~0ULL) | (r->n[3] != ~0ULL));
r->n[0] -= (~mask & LAST_LIMB);
r->n[1] &= mask;
r->n[2] &= mask;
r->n[3] &= mask;
assert(r->n[4] == 0);
#ifdef VERIFY
r->normalized = 1;
#endif
}
void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
#ifdef VERIFY
r->reduced = 1;
r->normalized = 1;
#endif
}
// TODO: not constant time!
int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0);
}
int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
return a->n[0] & 1;
}
// TODO: not constant time!
int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
#ifdef VERIFY
assert(a->normalized);
assert(b->normalized);
#endif
return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3]);
}
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
for (int i=0; i<32; i++) {
r->n[i/8] |= (uint64_t)a[31-i] << (i&7)*8;
}
#ifdef VERIFY
r->reduced = 1;
r->normalized = 0;
#endif
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
for (int i=0; i<32; i++) {
r[31-i] = a->n[i/8] >> ((i&7)*8);
}
}
void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *ac, int m) {
secp256k1_fe_t a = *ac;
secp256k1_fe_reduce(&a);
unsigned __int128 c = (unsigned __int128)(~a.n[0]) + LAST_LIMB + 1;
r->n[0] = c;
c = (c >> 64) + (~a.n[1]) + FULL_LIMB;
r->n[1] = c;
c = (c >> 64) + (~a.n[2]) + FULL_LIMB;
r->n[2] = c;
c = (c >> 64) + (~a.n[3]) + FULL_LIMB;
r->n[3] = c;
r->n[4] = 0;
#ifdef VERIFY
r->reduced = 1;
r->normalized = 0;
#endif
}
void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
#ifdef VERIFY
r->reduced = 0;
r->normalized = 0;
#endif
unsigned __int128 c = (unsigned __int128)r->n[0] * a;
r->n[0] = c;
c = (c >> 64) + (unsigned __int128)r->n[1] * a;
r->n[1] = c;
c = (c >> 64) + (unsigned __int128)r->n[2] * a;
r->n[2] = c;
c = (c >> 64) + (unsigned __int128)r->n[3] * a;
r->n[3] = c;
c = (c >> 64) + (unsigned __int128)r->n[4] * a;
r->n[4] = c;
}
void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
r->reduced = 0;
r->normalized = 0;
#endif
unsigned __int128 c = (unsigned __int128)r->n[0] + a->n[0];
r->n[0] = c;
c = (unsigned __int128)r->n[1] + a->n[1] + (c >> 64);
r->n[1] = c;
c = (unsigned __int128)r->n[2] + a->n[2] + (c >> 64);
r->n[2] = c;
c = (unsigned __int128)r->n[3] + a->n[3] + (c >> 64);
r->n[3] = c;
c = (unsigned __int128)r->n[4] + a->n[4] + (c >> 64);
r->n[4] = c;
assert((c >> 64) == 0);
}
#if 0
#define muladd_c3(a,b,c0,c1,c2) { \
unsigned __int128 q1 = ((unsigned __int128)(a)) * (b) + (c0); \
(c0) = q1; \
unsigned __int128 q2 = (q1 >> 64) + (c1) + (((unsigned __int128)(c2)) << 64); \
(c1) = q2; \
(c2) = q2 >> 64; \
}
#define sqradd_c3(a,c0,c1,c2) muladd_c3(a,a,c0,c1,c2)
/*#define muladd_c3(a,b,c0,c1,c2) { \
unsigned __int128 q = (unsigned __int128)(a) * (b) + (c0); \
(c0) = q; \
(c1) += (q >> 64); \
(c2) += ((c1) < (q >> 64))?1:0; \
}*/
#define muladd2_c3(a,b,c0,c1,c2) { \
unsigned __int128 q = (unsigned __int128)(a) * (b); \
uint64_t t1 = (q >> 64); \
uint64_t t0 = q; \
uint64_t t2 = t1+t1; (c2) += (t2<t1)?1:0; \
t1 = t0+t0; t2 += (t1<t0)?1:0; \
(c0) += t1; t2 += ((c0)<t1)?1:0; \
(c1) += t2; (c2) += ((c1)<t2)?1:0; \
}
/*#define muladd2_c3(a,b,c0,c1,c2) { \
muladd_c3(a,b,c0,c1,c2); \
muladd_c3(a,b,c0,c1,c2); \
}*/
#else
#define muladd_c3(a,b,c0,c1,c2) { \
register uint64_t t1, t2; \
asm ("mulq %3" \
: "=a"(t1),"=d"(t2) \
: "a"(a),"m"(b) \
: "cc"); \
asm ("addq %2,%0; adcq %3,%1" \
: "+r"(c0),"+d"(t2) \
: "a"(t1),"g"(0) \
: "cc"); \
asm ("addq %2,%0; adcq %3,%1" \
: "+r"(c1),"+r"(c2) \
: "d"(t2),"g"(0) \
: "cc"); \
}
#define sqradd_c3(a,c0,c1,c2) { \
register uint64_t t1, t2; \
asm ("mulq %2" \
: "=a"(t1),"=d"(t2) \
: "a"(a) \
: "cc"); \
asm ("addq %2,%0; adcq %3,%1" \
: "+r"(c0),"+d"(t2) \
: "a"(t1),"g"(0) \
: "cc"); \
asm ("addq %2,%0; adcq %3,%1" \
: "+r"(c1),"+r"(c2) \
: "d"(t2),"g"(0) \
: "cc"); \
}
#define muladd2_c3(a,b,c0,c1,c2) { \
register uint64_t t1, t2; \
asm ("mulq %3" \
: "=a"(t1),"=d"(t2) \
: "a"(a),"m"(b) \
: "cc"); \
asm ("addq %0,%0; adcq %2,%1" \
: "+d"(t2),"+r"(c2) \
: "g"(0) \
: "cc"); \
asm ("addq %0,%0; adcq %2,%1" \
: "+a"(t1),"+d"(t2) \
: "g"(0) \
: "cc"); \
asm ("addq %2,%0; adcq %3,%1" \
: "+r"(c0),"+d"(t2) \
: "a"(t1),"g"(0) \
: "cc"); \
asm ("addq %2,%0; adcq %3,%1" \
: "+r"(c1),"+r"(c2) \
: "d"(t2),"g"(0) \
: "cc"); \
}
#endif
#define mul_c2(a,b,c0,c1) { \
unsigned __int128 q = (unsigned __int128)(a) * (b); \
(c0) = q; \
(c1) = (q >> 64); \
}
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *ac, const secp256k1_fe_t *bc) {
secp256k1_fe_t a = *ac, b = *bc;
secp256k1_fe_reduce(&a);
secp256k1_fe_reduce(&b);
#ifdef USE_FIELD_5X64_ASM
secp256k1_fe_mul_inner((&a)->n,(&b)->n,r->n);
#else
uint64_t c1,c2,c3;
c3=0;
mul_c2(a.n[0], b.n[0], c1, c2);
uint64_t r0 = c1; c1 = 0;
muladd_c3(a.n[0], b.n[1], c2, c3, c1);
muladd_c3(a.n[1], b.n[0], c2, c3, c1);
uint64_t r1 = c2; c2 = 0;
muladd_c3(a.n[2], b.n[0], c3, c1, c2);
muladd_c3(a.n[1], b.n[1], c3, c1, c2);
muladd_c3(a.n[0], b.n[2], c3, c1, c2);
uint64_t r2 = c3; c3 = 0;
muladd_c3(a.n[0], b.n[3], c1, c2, c3);
muladd_c3(a.n[1], b.n[2], c1, c2, c3);
muladd_c3(a.n[2], b.n[1], c1, c2, c3);
muladd_c3(a.n[3], b.n[0], c1, c2, c3);
uint64_t r3 = c1; c1 = 0;
muladd_c3(a.n[3], b.n[1], c2, c3, c1);
muladd_c3(a.n[2], b.n[2], c2, c3, c1);
muladd_c3(a.n[1], b.n[3], c2, c3, c1);
uint64_t r4 = c2; c2 = 0;
muladd_c3(a.n[2], b.n[3], c3, c1, c2);
muladd_c3(a.n[3], b.n[2], c3, c1, c2);
uint64_t r5 = c3; c3 = 0;
muladd_c3(a.n[3], b.n[3], c1, c2, c3);
uint64_t r6 = c1;
uint64_t r7 = c2;
assert(c3 == 0);
unsigned __int128 c = (unsigned __int128)r4 * COMP_LIMB + r0;
r->n[0] = c;
c = (unsigned __int128)r5 * COMP_LIMB + r1 + (c >> 64);
r->n[1] = c;
c = (unsigned __int128)r6 * COMP_LIMB + r2 + (c >> 64);
r->n[2] = c;
c = (unsigned __int128)r7 * COMP_LIMB + r3 + (c >> 64);
r->n[3] = c;
r->n[4] = c >> 64;
#endif
#ifdef VERIFY
r->normalized = 0;
r->reduced = 0;
#endif
secp256k1_fe_reduce(r);
}
/*void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
secp256k1_fe_mul(r, a, a);
}*/
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *ac) {
secp256k1_fe_t a = *ac;
secp256k1_fe_reduce(&a);
#ifdef USE_FIELD_5X64_ASM
secp256k1_fe_sqr_inner((&a)->n,r->n);
#else
uint64_t c1,c2,c3;
c3=0;
mul_c2(a.n[0], a.n[0], c1, c2);
uint64_t r0 = c1; c1 = 0;
muladd2_c3(a.n[0], a.n[1], c2, c3, c1);
uint64_t r1 = c2; c2 = 0;
muladd2_c3(a.n[2], a.n[0], c3, c1, c2);
sqradd_c3(a.n[1], c3, c1, c2);
uint64_t r2 = c3; c3 = 0;
muladd2_c3(a.n[0], a.n[3], c1, c2, c3);
muladd2_c3(a.n[1], a.n[2], c1, c2, c3);
uint64_t r3 = c1; c1 = 0;
muladd2_c3(a.n[3], a.n[1], c2, c3, c1);
sqradd_c3(a.n[2], c2, c3, c1);
uint64_t r4 = c2; c2 = 0;
muladd2_c3(a.n[2], a.n[3], c3, c1, c2);
uint64_t r5 = c3; c3 = 0;
sqradd_c3(a.n[3], c1, c2, c3);
uint64_t r6 = c1;
uint64_t r7 = c2;
assert(c3 == 0);
unsigned __int128 c = (unsigned __int128)r4 * COMP_LIMB + r0;
r->n[0] = c;
c = (unsigned __int128)r5 * COMP_LIMB + r1 + (c >> 64);
r->n[1] = c;
c = (unsigned __int128)r6 * COMP_LIMB + r2 + (c >> 64);
r->n[2] = c;
c = (unsigned __int128)r7 * COMP_LIMB + r3 + (c >> 64);
r->n[3] = c;
r->n[4] = c >> 64;
#endif
#ifdef VERIFY
r->normalized = 0;
r->reduced = 0;
#endif
secp256k1_fe_reduce(r);
}
#endif

View File

@ -0,0 +1,11 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
void __attribute__ ((sysv_abi)) secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r);
void __attribute__ ((sysv_abi)) secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r);
#endif

View File

@ -0,0 +1,155 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
#define _SECP256K1_FIELD_REPR_IMPL_H_
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "../num.h"
#include "../field.h"
static mp_limb_t secp256k1_field_p[FIELD_LIMBS];
static mp_limb_t secp256k1_field_pc[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS];
void static secp256k1_fe_inner_start(void) {
for (int i=0; i<(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; i++)
secp256k1_field_pc[i] = 0;
secp256k1_field_pc[0] += 0x3D1UL;
secp256k1_field_pc[32/GMP_NUMB_BITS] += (1UL << (32 % GMP_NUMB_BITS));
for (int i=0; i<FIELD_LIMBS; i++) {
secp256k1_field_p[i] = 0;
}
mpn_sub(secp256k1_field_p, secp256k1_field_p, FIELD_LIMBS, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS);
}
void static secp256k1_fe_inner_stop(void) {
}
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
if (r->n[FIELD_LIMBS] != 0) {
#if (GMP_NUMB_BITS >= 40)
mp_limb_t carry = mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x1000003D1ULL * r->n[FIELD_LIMBS]);
mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x1000003D1ULL * carry);
#else
mp_limb_t carry = mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x3D1UL * r->n[FIELD_LIMBS]) +
mpn_add_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), r->n[FIELD_LIMBS] << (32 % GMP_NUMB_BITS));
mpn_add_1(r->n, r->n, FIELD_LIMBS, 0x3D1UL * carry);
mpn_add_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), carry << (32%GMP_NUMB_BITS));
#endif
r->n[FIELD_LIMBS] = 0;
}
if (mpn_cmp(r->n, secp256k1_field_p, FIELD_LIMBS) >= 0)
mpn_sub(r->n, r->n, FIELD_LIMBS, secp256k1_field_p, FIELD_LIMBS);
}
void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
r->n[0] = a;
for (int i=1; i<FIELD_LIMBS+1; i++)
r->n[i] = 0;
}
int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
int ret = 1;
for (int i=0; i<FIELD_LIMBS+1; i++)
ret &= (a->n[i] == 0);
return ret;
}
int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
return a->n[0] & 1;
}
int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
int ret = 1;
for (int i=0; i<FIELD_LIMBS+1; i++)
ret &= (a->n[i] == b->n[i]);
return ret;
}
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
for (int i=0; i<FIELD_LIMBS+1; i++)
r->n[i] = 0;
for (int i=0; i<256; i++) {
int limb = i/GMP_NUMB_BITS;
int shift = i%GMP_NUMB_BITS;
r->n[limb] |= (mp_limb_t)((a[31-i/8] >> (i%8)) & 0x1) << shift;
}
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
for (int i=0; i<32; i++) {
int c = 0;
for (int j=0; j<8; j++) {
int limb = (8*i+j)/GMP_NUMB_BITS;
int shift = (8*i+j)%GMP_NUMB_BITS;
c |= ((a->n[limb] >> shift) & 0x1) << j;
}
r[31-i] = c;
}
}
void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
*r = *a;
secp256k1_fe_normalize(r);
for (int i=0; i<FIELD_LIMBS; i++)
r->n[i] = ~(r->n[i]);
#if (GMP_NUMB_BITS >= 33)
mpn_sub_1(r->n, r->n, FIELD_LIMBS, 0x1000003D0ULL);
#else
mpn_sub_1(r->n, r->n, FIELD_LIMBS, 0x3D0UL);
mpn_sub_1(r->n+(32/GMP_NUMB_BITS), r->n+(32/GMP_NUMB_BITS), FIELD_LIMBS-(32/GMP_NUMB_BITS), 0x1UL << (32%GMP_NUMB_BITS));
#endif
}
void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
mpn_mul_1(r->n, r->n, FIELD_LIMBS+1, a);
}
void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
mpn_add(r->n, r->n, FIELD_LIMBS+1, a->n, FIELD_LIMBS+1);
}
void static secp256k1_fe_reduce(secp256k1_fe_t *r, mp_limb_t *tmp) {
// <A1 A2 A3 A4> <B1 B2 B3 B4>
// B1 B2 B3 B4
// + C * A1 A2 A3 A4
// + A1 A2 A3 A4
#if (GMP_NUMB_BITS >= 33)
mp_limb_t o = mpn_addmul_1(tmp, tmp+FIELD_LIMBS, FIELD_LIMBS, 0x1000003D1ULL);
#else
mp_limb_t o = mpn_addmul_1(tmp, tmp+FIELD_LIMBS, FIELD_LIMBS, 0x3D1UL) +
mpn_addmul_1(tmp+(32/GMP_NUMB_BITS), tmp+FIELD_LIMBS, FIELD_LIMBS-(32/GMP_NUMB_BITS), 0x1UL << (32%GMP_NUMB_BITS));
#endif
mp_limb_t q[1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS];
q[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS] = mpn_mul_1(q, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS, o);
#if (GMP_NUMB_BITS <= 32)
mp_limb_t o2 = tmp[2*FIELD_LIMBS-(32/GMP_NUMB_BITS)] << (32%GMP_NUMB_BITS);
q[(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS] += mpn_addmul_1(q, secp256k1_field_pc, (33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS, o2);
#endif
r->n[FIELD_LIMBS] = mpn_add(r->n, tmp, FIELD_LIMBS, q, 1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS);
}
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
secp256k1_fe_t ac = *a;
secp256k1_fe_t bc = *b;
secp256k1_fe_normalize(&ac);
secp256k1_fe_normalize(&bc);
mp_limb_t tmp[2*FIELD_LIMBS];
mpn_mul_n(tmp, ac.n, bc.n, FIELD_LIMBS);
secp256k1_fe_reduce(r, tmp);
}
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
secp256k1_fe_t ac = *a;
secp256k1_fe_normalize(&ac);
mp_limb_t tmp[2*FIELD_LIMBS];
mpn_sqr(tmp, ac.n, FIELD_LIMBS);
secp256k1_fe_reduce(r, tmp);
}
#endif

View File

@ -0,0 +1,397 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_GROUP_IMPL_H_
#define _SECP256K1_GROUP_IMPL_H_
#include <string.h>
#include "../num.h"
#include "../field.h"
#include "../group.h"
void static secp256k1_ge_set_infinity(secp256k1_ge_t *r) {
r->infinity = 1;
}
void static secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
r->infinity = 0;
r->x = *x;
r->y = *y;
}
int static secp256k1_ge_is_infinity(const secp256k1_ge_t *a) {
return a->infinity;
}
void static secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) {
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
secp256k1_fe_normalize(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
}
void static secp256k1_ge_get_hex(char *r, int *rlen, const secp256k1_ge_t *a) {
char cx[65]; int lx=65;
char cy[65]; int ly=65;
secp256k1_fe_get_hex(cx, &lx, &a->x);
secp256k1_fe_get_hex(cy, &ly, &a->y);
lx = strlen(cx);
ly = strlen(cy);
int len = lx + ly + 3 + 1;
if (*rlen < len) {
*rlen = len;
return;
}
*rlen = len;
r[0] = '(';
memcpy(r+1, cx, lx);
r[1+lx] = ',';
memcpy(r+2+lx, cy, ly);
r[2+lx+ly] = ')';
r[3+lx+ly] = 0;
}
void static secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) {
secp256k1_fe_inv_var(&a->z, &a->z);
secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z);
secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &a->z, &z2);
secp256k1_fe_mul(&a->x, &a->x, &z2);
secp256k1_fe_mul(&a->y, &a->y, &z3);
secp256k1_fe_set_int(&a->z, 1);
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
}
void static secp256k1_gej_set_infinity(secp256k1_gej_t *r) {
r->infinity = 1;
}
void static secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
r->infinity = 0;
r->x = *x;
r->y = *y;
secp256k1_fe_set_int(&r->z, 1);
}
void static secp256k1_ge_set_xo(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) {
r->x = *x;
secp256k1_fe_t x2; secp256k1_fe_sqr(&x2, x);
secp256k1_fe_t x3; secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0;
secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7);
secp256k1_fe_add(&c, &x3);
secp256k1_fe_sqrt(&r->y, &c);
secp256k1_fe_normalize(&r->y);
if (secp256k1_fe_is_odd(&r->y) != odd)
secp256k1_fe_negate(&r->y, &r->y, 1);
}
void static secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) {
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
secp256k1_fe_set_int(&r->z, 1);
}
void static secp256k1_gej_get_x(secp256k1_fe_t *r, const secp256k1_gej_t *a) {
secp256k1_fe_t zi2; secp256k1_fe_inv_var(&zi2, &a->z); secp256k1_fe_sqr(&zi2, &zi2);
secp256k1_fe_mul(r, &a->x, &zi2);
}
void static secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
r->z = a->z;
secp256k1_fe_normalize(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
}
int static secp256k1_gej_is_infinity(const secp256k1_gej_t *a) {
return a->infinity;
}
int static secp256k1_gej_is_valid(const secp256k1_gej_t *a) {
if (a->infinity)
return 0;
// y^2 = x^3 + 7
// (Y/Z^3)^2 = (X/Z^2)^3 + 7
// Y^2 / Z^6 = X^3 / Z^6 + 7
// Y^2 = X^3 + 7*Z^6
secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &a->y);
secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &a->z);
secp256k1_fe_t z6; secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
secp256k1_fe_mul_int(&z6, 7);
secp256k1_fe_add(&x3, &z6);
secp256k1_fe_normalize(&y2);
secp256k1_fe_normalize(&x3);
return secp256k1_fe_equal(&y2, &x3);
}
int static secp256k1_ge_is_valid(const secp256k1_ge_t *a) {
if (a->infinity)
return 0;
// y^2 = x^3 + 7
secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &a->y);
secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7);
secp256k1_fe_add(&x3, &c);
secp256k1_fe_normalize(&y2);
secp256k1_fe_normalize(&x3);
return secp256k1_fe_equal(&y2, &x3);
}
void static secp256k1_gej_double(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
secp256k1_fe_t t5 = a->y;
secp256k1_fe_normalize(&t5);
if (a->infinity || secp256k1_fe_is_zero(&t5)) {
r->infinity = 1;
return;
}
secp256k1_fe_t t1,t2,t3,t4;
secp256k1_fe_mul(&r->z, &t5, &a->z);
secp256k1_fe_mul_int(&r->z, 2); // Z' = 2*Y*Z (2)
secp256k1_fe_sqr(&t1, &a->x);
secp256k1_fe_mul_int(&t1, 3); // T1 = 3*X^2 (3)
secp256k1_fe_sqr(&t2, &t1); // T2 = 9*X^4 (1)
secp256k1_fe_sqr(&t3, &t5);
secp256k1_fe_mul_int(&t3, 2); // T3 = 2*Y^2 (2)
secp256k1_fe_sqr(&t4, &t3);
secp256k1_fe_mul_int(&t4, 2); // T4 = 8*Y^4 (2)
secp256k1_fe_mul(&t3, &a->x, &t3); // T3 = 2*X*Y^2 (1)
r->x = t3;
secp256k1_fe_mul_int(&r->x, 4); // X' = 8*X*Y^2 (4)
secp256k1_fe_negate(&r->x, &r->x, 4); // X' = -8*X*Y^2 (5)
secp256k1_fe_add(&r->x, &t2); // X' = 9*X^4 - 8*X*Y^2 (6)
secp256k1_fe_negate(&t2, &t2, 1); // T2 = -9*X^4 (2)
secp256k1_fe_mul_int(&t3, 6); // T3 = 12*X*Y^2 (6)
secp256k1_fe_add(&t3, &t2); // T3 = 12*X*Y^2 - 9*X^4 (8)
secp256k1_fe_mul(&r->y, &t1, &t3); // Y' = 36*X^3*Y^2 - 27*X^6 (1)
secp256k1_fe_negate(&t2, &t4, 2); // T2 = -8*Y^4 (3)
secp256k1_fe_add(&r->y, &t2); // Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4)
r->infinity = 0;
}
void static secp256k1_gej_add(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
if (a->infinity) {
*r = *b;
return;
}
if (b->infinity) {
*r = *a;
return;
}
r->infinity = 0;
secp256k1_fe_t z22; secp256k1_fe_sqr(&z22, &b->z);
secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z);
secp256k1_fe_t u1; secp256k1_fe_mul(&u1, &a->x, &z22);
secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12);
secp256k1_fe_t s1; secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z);
secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
secp256k1_fe_normalize(&u1);
secp256k1_fe_normalize(&u2);
if (secp256k1_fe_equal(&u1, &u2)) {
secp256k1_fe_normalize(&s1);
secp256k1_fe_normalize(&s2);
if (secp256k1_fe_equal(&s1, &s2)) {
secp256k1_gej_double(r, a);
} else {
r->infinity = 1;
}
return;
}
secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i);
secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h);
secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2);
secp256k1_fe_mul(&r->z, &a->z, &b->z); secp256k1_fe_mul(&r->z, &r->z, &h);
secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2);
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
secp256k1_fe_add(&r->y, &h3);
}
void static secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) {
if (a->infinity) {
r->infinity = b->infinity;
r->x = b->x;
r->y = b->y;
secp256k1_fe_set_int(&r->z, 1);
return;
}
if (b->infinity) {
*r = *a;
return;
}
r->infinity = 0;
secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &a->z);
secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize(&u1);
secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12);
secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize(&s1);
secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
secp256k1_fe_normalize(&u1);
secp256k1_fe_normalize(&u2);
if (secp256k1_fe_equal(&u1, &u2)) {
secp256k1_fe_normalize(&s1);
secp256k1_fe_normalize(&s2);
if (secp256k1_fe_equal(&s1, &s2)) {
secp256k1_gej_double(r, a);
} else {
r->infinity = 1;
}
return;
}
secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i);
secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h);
secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2);
r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h);
secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2);
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
secp256k1_fe_add(&r->y, &h3);
}
void static secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a) {
secp256k1_gej_t c = *a;
secp256k1_ge_t t; secp256k1_ge_set_gej(&t, &c);
secp256k1_ge_get_hex(r, rlen, &t);
}
void static secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
const secp256k1_fe_t *beta = &secp256k1_ge_consts->beta;
*r = *a;
secp256k1_fe_mul(&r->x, &r->x, beta);
}
void static secp256k1_gej_split_exp(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a) {
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
secp256k1_num_t bnc1, bnc2, bnt1, bnt2, bnn2;
secp256k1_num_init(&bnc1);
secp256k1_num_init(&bnc2);
secp256k1_num_init(&bnt1);
secp256k1_num_init(&bnt2);
secp256k1_num_init(&bnn2);
secp256k1_num_copy(&bnn2, &c->order);
secp256k1_num_shift(&bnn2, 1);
secp256k1_num_mul(&bnc1, a, &c->a1b2);
secp256k1_num_add(&bnc1, &bnc1, &bnn2);
secp256k1_num_div(&bnc1, &bnc1, &c->order);
secp256k1_num_mul(&bnc2, a, &c->b1);
secp256k1_num_add(&bnc2, &bnc2, &bnn2);
secp256k1_num_div(&bnc2, &bnc2, &c->order);
secp256k1_num_mul(&bnt1, &bnc1, &c->a1b2);
secp256k1_num_mul(&bnt2, &bnc2, &c->a2);
secp256k1_num_add(&bnt1, &bnt1, &bnt2);
secp256k1_num_sub(r1, a, &bnt1);
secp256k1_num_mul(&bnt1, &bnc1, &c->b1);
secp256k1_num_mul(&bnt2, &bnc2, &c->a1b2);
secp256k1_num_sub(r2, &bnt1, &bnt2);
secp256k1_num_free(&bnc1);
secp256k1_num_free(&bnc2);
secp256k1_num_free(&bnt1);
secp256k1_num_free(&bnt2);
secp256k1_num_free(&bnn2);
}
void static secp256k1_ge_start(void) {
static const unsigned char secp256k1_ge_consts_order[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
};
static const unsigned char secp256k1_ge_consts_g_x[] = {
0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,
0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07,
0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,
0x59,0xF2,0x81,0x5B,0x16,0xF8,0x17,0x98
};
static const unsigned char secp256k1_ge_consts_g_y[] = {
0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,
0x5D,0xA4,0xFB,0xFC,0x0E,0x11,0x08,0xA8,
0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,
0x9C,0x47,0xD0,0x8F,0xFB,0x10,0xD4,0xB8
};
// properties of secp256k1's efficiently computable endomorphism
static const unsigned char secp256k1_ge_consts_lambda[] = {
0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,
0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,
0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72
};
static const unsigned char secp256k1_ge_consts_beta[] = {
0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10,
0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9,
0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95,
0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee
};
static const unsigned char secp256k1_ge_consts_a1b2[] = {
0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,
0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15
};
static const unsigned char secp256k1_ge_consts_b1[] = {
0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,
0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3
};
static const unsigned char secp256k1_ge_consts_a2[] = {
0x01,
0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,
0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8
};
if (secp256k1_ge_consts == NULL) {
secp256k1_ge_consts_t *ret = (secp256k1_ge_consts_t*)malloc(sizeof(secp256k1_ge_consts_t));
secp256k1_num_init(&ret->order);
secp256k1_num_init(&ret->half_order);
secp256k1_num_init(&ret->lambda);
secp256k1_num_init(&ret->a1b2);
secp256k1_num_init(&ret->a2);
secp256k1_num_init(&ret->b1);
secp256k1_num_set_bin(&ret->order, secp256k1_ge_consts_order, sizeof(secp256k1_ge_consts_order));
secp256k1_num_set_bin(&ret->lambda, secp256k1_ge_consts_lambda, sizeof(secp256k1_ge_consts_lambda));
secp256k1_num_set_bin(&ret->a1b2, secp256k1_ge_consts_a1b2, sizeof(secp256k1_ge_consts_a1b2));
secp256k1_num_set_bin(&ret->a2, secp256k1_ge_consts_a2, sizeof(secp256k1_ge_consts_a2));
secp256k1_num_set_bin(&ret->b1, secp256k1_ge_consts_b1, sizeof(secp256k1_ge_consts_b1));
secp256k1_num_copy(&ret->half_order, &ret->order);
secp256k1_num_shift(&ret->half_order, 1);
secp256k1_fe_set_b32(&ret->beta, secp256k1_ge_consts_beta);
secp256k1_fe_t g_x, g_y;
secp256k1_fe_set_b32(&g_x, secp256k1_ge_consts_g_x);
secp256k1_fe_set_b32(&g_y, secp256k1_ge_consts_g_y);
secp256k1_ge_set_xy(&ret->g, &g_x, &g_y);
secp256k1_ge_consts = ret;
}
}
void static secp256k1_ge_stop(void) {
if (secp256k1_ge_consts != NULL) {
secp256k1_ge_consts_t *c = (secp256k1_ge_consts_t*)secp256k1_ge_consts;
secp256k1_num_free(&c->order);
secp256k1_num_free(&c->half_order);
secp256k1_num_free(&c->lambda);
secp256k1_num_free(&c->a1b2);
secp256k1_num_free(&c->a2);
secp256k1_num_free(&c->b1);
free((void*)c);
secp256k1_ge_consts = NULL;
}
}
#endif

View File

@ -0,0 +1,18 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_NUM_IMPL_H_
#define _SECP256K1_NUM_IMPL_H_
#include "../num.h"
#if defined(USE_NUM_GMP)
#include "num_gmp.h"
#elif defined(USE_NUM_OPENSSL)
#include "num_openssl.h"
#else
#error "Please select num implementation"
#endif
#endif

View File

@ -0,0 +1,346 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_NUM_REPR_IMPL_H_
#define _SECP256K1_NUM_REPR_IMPL_H_
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <gmp.h>
#include "num.h"
#ifdef VERIFY
void static secp256k1_num_sanity(const secp256k1_num_t *a) {
assert(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0));
}
#else
#define secp256k1_num_sanity(a) do { } while(0)
#endif
void static secp256k1_num_init(secp256k1_num_t *r) {
r->neg = 0;
r->limbs = 1;
r->data[0] = 0;
}
void static secp256k1_num_free(secp256k1_num_t *r) {
}
void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
*r = *a;
}
int static secp256k1_num_bits(const secp256k1_num_t *a) {
int ret=(a->limbs-1)*GMP_NUMB_BITS;
mp_limb_t x=a->data[a->limbs-1];
while (x) {
x >>= 1;
ret++;
}
return ret;
}
void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
unsigned char tmp[65];
int len = 0;
if (a->limbs>1 || a->data[0] != 0) {
len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs);
}
int shift = 0;
while (shift < len && tmp[shift] == 0) shift++;
assert(len-shift <= rlen);
memset(r, 0, rlen - len + shift);
if (len > shift)
memcpy(r + rlen - len + shift, tmp + shift, len - shift);
}
void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
assert(alen > 0);
assert(alen <= 64);
int len = mpn_set_str(r->data, a, alen, 256);
assert(len <= NUM_LIMBS*2);
r->limbs = len;
r->neg = 0;
while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
}
void static secp256k1_num_set_int(secp256k1_num_t *r, int a) {
r->limbs = 1;
r->neg = (a < 0);
r->data[0] = (a < 0) ? -a : a;
}
void static secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs);
r->limbs = a->limbs;
if (c != 0) {
assert(r->limbs < 2*NUM_LIMBS);
r->data[r->limbs++] = c;
}
}
void static secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs);
assert(c == 0);
r->limbs = a->limbs;
while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
}
void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
secp256k1_num_sanity(r);
secp256k1_num_sanity(m);
if (r->limbs >= m->limbs) {
mp_limb_t t[2*NUM_LIMBS];
mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs);
r->limbs = m->limbs;
while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
}
if (r->neg && (r->limbs > 1 || r->data[0] != 0)) {
secp256k1_num_sub_abs(r, m, r);
r->neg = 0;
}
}
void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
secp256k1_num_sanity(a);
secp256k1_num_sanity(m);
// mpn_gcdext computes: (G,S) = gcdext(U,V), where
// * G = gcd(U,V)
// * G = U*S + V*T
// * U has equal or more limbs than V, and V has no padding
// If we set U to be (a padded version of) a, and V = m:
// G = a*S + m*T
// G = a*S mod m
// Assuming G=1:
// S = 1/a mod m
assert(m->limbs <= NUM_LIMBS);
assert(m->data[m->limbs-1] != 0);
mp_limb_t g[NUM_LIMBS+1];
mp_limb_t u[NUM_LIMBS+1];
mp_limb_t v[NUM_LIMBS+1];
for (int i=0; i < m->limbs; i++) {
u[i] = (i < a->limbs) ? a->data[i] : 0;
v[i] = m->data[i];
}
mp_size_t sn = NUM_LIMBS+1;
mp_size_t gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
assert(gn == 1);
assert(g[0] == 1);
r->neg = a->neg ^ m->neg;
if (sn < 0) {
mpn_sub(r->data, m->data, m->limbs, r->data, -sn);
r->limbs = m->limbs;
while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
} else {
r->limbs = sn;
}
}
int static secp256k1_num_is_zero(const secp256k1_num_t *a) {
return (a->limbs == 1 && a->data[0] == 0);
}
int static secp256k1_num_is_odd(const secp256k1_num_t *a) {
return a->data[0] & 1;
}
int static secp256k1_num_is_neg(const secp256k1_num_t *a) {
return (a->limbs > 1 || a->data[0] != 0) && a->neg;
}
int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
if (a->limbs > b->limbs) return 1;
if (a->limbs < b->limbs) return -1;
return mpn_cmp(a->data, b->data, a->limbs);
}
void static secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) {
if (!(b->neg ^ bneg ^ a->neg)) { // a and b have the same sign
r->neg = a->neg;
if (a->limbs >= b->limbs) {
secp256k1_num_add_abs(r, a, b);
} else {
secp256k1_num_add_abs(r, b, a);
}
} else {
if (secp256k1_num_cmp(a, b) > 0) {
r->neg = a->neg;
secp256k1_num_sub_abs(r, a, b);
} else {
r->neg = b->neg ^ bneg;
secp256k1_num_sub_abs(r, b, a);
}
}
}
void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
secp256k1_num_sanity(a);
secp256k1_num_sanity(b);
secp256k1_num_subadd(r, a, b, 0);
}
void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
secp256k1_num_sanity(a);
secp256k1_num_sanity(b);
secp256k1_num_subadd(r, a, b, 1);
}
void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
secp256k1_num_sanity(a);
secp256k1_num_sanity(b);
mp_limb_t tmp[2*NUM_LIMBS+1];
assert(a->limbs + b->limbs <= 2*NUM_LIMBS+1);
if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) {
r->limbs = 1;
r->neg = 0;
r->data[0] = 0;
return;
}
if (a->limbs >= b->limbs)
mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs);
else
mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs);
r->limbs = a->limbs + b->limbs;
if (r->limbs > 1 && tmp[r->limbs - 1]==0) r->limbs--;
assert(r->limbs <= 2*NUM_LIMBS);
mpn_copyi(r->data, tmp, r->limbs);
r->neg = a->neg ^ b->neg;
}
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
secp256k1_num_sanity(a);
secp256k1_num_sanity(b);
if (b->limbs > a->limbs) {
r->limbs = 1;
r->data[0] = 0;
r->neg = 0;
return;
}
mp_limb_t quo[2*NUM_LIMBS+1];
mp_limb_t rem[2*NUM_LIMBS+1];
mpn_tdiv_qr(quo, rem, 0, a->data, a->limbs, b->data, b->limbs);
mpn_copyi(r->data, quo, a->limbs - b->limbs + 1);
r->limbs = a->limbs - b->limbs + 1;
while (r->limbs > 1 && r->data[r->limbs - 1]==0) r->limbs--;
r->neg = a->neg ^ b->neg;
}
void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
secp256k1_num_mul(r, a, b);
secp256k1_num_mod(r, m);
}
int static secp256k1_num_shift(secp256k1_num_t *r, int bits) {
assert(bits <= GMP_NUMB_BITS);
mp_limb_t ret = mpn_rshift(r->data, r->data, r->limbs, bits);
if (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--;
ret >>= (GMP_NUMB_BITS - bits);
return ret;
}
int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) {
return (a->limbs*GMP_NUMB_BITS > pos) && ((a->data[pos/GMP_NUMB_BITS] >> (pos % GMP_NUMB_BITS)) & 1);
}
void static secp256k1_num_inc(secp256k1_num_t *r) {
mp_limb_t ret = mpn_add_1(r->data, r->data, r->limbs, (mp_limb_t)1);
if (ret) {
assert(r->limbs < 2*NUM_LIMBS);
r->data[r->limbs++] = ret;
}
}
void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) {
static const unsigned char cvt[256] = {
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,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,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0
};
unsigned char num[257] = {};
for (int i=0; i<alen; i++) {
num[i] = cvt[a[i]];
}
r->limbs = mpn_set_str(r->data, num, alen, 16);
while (r->limbs > 1 && r->data[r->limbs-1] == 0) r->limbs--;
}
void static secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a) {
static const unsigned char cvt[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
unsigned char *tmp = malloc(257);
mp_size_t len = mpn_get_str(tmp, 16, (mp_limb_t*)a->data, a->limbs);
assert(len <= rlen);
for (int i=0; i<len; i++) {
assert(rlen-len+i >= 0);
assert(rlen-len+i < rlen);
assert(tmp[i] >= 0);
assert(tmp[i] < 16);
r[rlen-len+i] = cvt[tmp[i]];
}
for (int i=0; i<rlen-len; i++) {
assert(i >= 0);
assert(i < rlen);
r[i] = cvt[0];
}
free(tmp);
}
void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) {
assert(bits > 0);
rh->neg = a->neg;
if (bits >= a->limbs * GMP_NUMB_BITS) {
*rl = *a;
rh->limbs = 1;
rh->data[0] = 0;
return;
}
rl->limbs = 0;
rl->neg = a->neg;
int left = bits;
while (left >= GMP_NUMB_BITS) {
rl->data[rl->limbs] = a->data[rl->limbs];
rl->limbs++;
left -= GMP_NUMB_BITS;
}
if (left == 0) {
mpn_copyi(rh->data, a->data + rl->limbs, a->limbs - rl->limbs);
rh->limbs = a->limbs - rl->limbs;
} else {
mpn_rshift(rh->data, a->data + rl->limbs, a->limbs - rl->limbs, left);
rh->limbs = a->limbs - rl->limbs;
while (rh->limbs>1 && rh->data[rh->limbs-1]==0) rh->limbs--;
}
if (left > 0) {
rl->data[rl->limbs] = a->data[rl->limbs] & ((((mp_limb_t)1) << left) - 1);
rl->limbs++;
}
while (rl->limbs>1 && rl->data[rl->limbs-1]==0) rl->limbs--;
}
void static secp256k1_num_negate(secp256k1_num_t *r) {
r->neg ^= 1;
}
#endif

View File

@ -0,0 +1,145 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_NUM_REPR_IMPL_H_
#define _SECP256K1_NUM_REPR_IMPL_H_
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include "../num.h"
void static secp256k1_num_init(secp256k1_num_t *r) {
BN_init(&r->bn);
}
void static secp256k1_num_free(secp256k1_num_t *r) {
BN_free(&r->bn);
}
void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
BN_copy(&r->bn, &a->bn);
}
void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
unsigned int size = BN_num_bytes(&a->bn);
assert(size <= rlen);
memset(r,0,rlen);
BN_bn2bin(&a->bn, r + rlen - size);
}
void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
BN_bin2bn(a, alen, &r->bn);
}
void static secp256k1_num_set_int(secp256k1_num_t *r, int a) {
BN_set_word(&r->bn, a < 0 ? -a : a);
BN_set_negative(&r->bn, a < 0);
}
void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
BN_CTX *ctx = BN_CTX_new();
BN_mod_inverse(&r->bn, &a->bn, &m->bn, ctx);
BN_CTX_free(ctx);
}
void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
BN_CTX *ctx = BN_CTX_new();
BN_mod_mul(&r->bn, &a->bn, &b->bn, &m->bn, ctx);
BN_CTX_free(ctx);
}
int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
return BN_cmp(&a->bn, &b->bn);
}
void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
BN_add(&r->bn, &a->bn, &b->bn);
}
void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
BN_sub(&r->bn, &a->bn, &b->bn);
}
void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
BN_CTX *ctx = BN_CTX_new();
BN_mul(&r->bn, &a->bn, &b->bn, ctx);
BN_CTX_free(ctx);
}
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
BN_CTX *ctx = BN_CTX_new();
BN_div(&r->bn, NULL, &a->bn, &b->bn, ctx);
BN_CTX_free(ctx);
}
void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) {
BN_CTX *ctx = BN_CTX_new();
BN_nnmod(&r->bn, &r->bn, &m->bn, ctx);
BN_CTX_free(ctx);
}
int static secp256k1_num_bits(const secp256k1_num_t *a) {
return BN_num_bits(&a->bn);
}
int static secp256k1_num_shift(secp256k1_num_t *r, int bits) {
int ret = BN_is_zero(&r->bn) ? 0 : r->bn.d[0] & ((1 << bits) - 1);
BN_rshift(&r->bn, &r->bn, bits);
return ret;
}
int static secp256k1_num_is_zero(const secp256k1_num_t *a) {
return BN_is_zero(&a->bn);
}
int static secp256k1_num_is_odd(const secp256k1_num_t *a) {
return BN_is_odd(&a->bn);
}
int static secp256k1_num_is_neg(const secp256k1_num_t *a) {
return BN_is_negative(&a->bn);
}
int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) {
return BN_is_bit_set(&a->bn, pos);
}
void static secp256k1_num_inc(secp256k1_num_t *r) {
BN_add_word(&r->bn, 1);
}
void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) {
char *str = (char*)malloc(alen+1);
memcpy(str, a, alen);
str[alen] = 0;
BIGNUM *pbn = &r->bn;
BN_hex2bn(&pbn, str);
free(str);
}
void static secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a) {
char *str = BN_bn2hex(&a->bn);
int len = strlen(str);
assert(rlen >= len);
for (int i=0; i<rlen-len; i++)
r[i] = '0';
memcpy(r+rlen-len, str, len);
OPENSSL_free(str);
}
void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) {
BN_copy(&rl->bn, &a->bn);
BN_rshift(&rh->bn, &a->bn, bits);
BN_mask_bits(&rl->bn, bits);
}
void static secp256k1_num_negate(secp256k1_num_t *r) {
BN_set_negative(&r->bn, !BN_is_negative(&r->bn));
}
#endif

View File

@ -0,0 +1,45 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_UTIL_IMPL_H_
#define _SECP256K1_UTIL_IMPL_H_
#include <stdint.h>
#include <string.h>
#include "../util.h"
static inline uint32_t secp256k1_rand32(void) {
static uint32_t Rz = 11, Rw = 11;
Rz = 36969 * (Rz & 0xFFFF) + (Rz >> 16);
Rw = 18000 * (Rw & 0xFFFF) + (Rw >> 16);
return (Rw << 16) + (Rw >> 16) + Rz;
}
static void secp256k1_rand256(unsigned char *b32) {
for (int i=0; i<8; i++) {
uint32_t r = secp256k1_rand32();
b32[i*4 + 0] = (r >> 0) & 0xFF;
b32[i*4 + 1] = (r >> 8) & 0xFF;
b32[i*4 + 2] = (r >> 16) & 0xFF;
b32[i*4 + 3] = (r >> 24) & 0xFF;
}
}
static void secp256k1_rand256_test(unsigned char *b32) {
int bits=0;
memset(b32, 0, 32);
while (bits < 256) {
uint32_t ent = secp256k1_rand32();
int now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31;
uint32_t val = 1 & (ent >> 11);
while (now > 0 && bits < 256) {
b32[bits / 8] |= val << (bits % 8);
now--;
bits++;
}
}
}
#endif

View File

@ -0,0 +1,60 @@
package org.bitcoin;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.google.common.base.Preconditions;
/**
* This class holds native methods to handle ECDSA verification.
* You can find an example library that can be used for this at
* https://github.com/sipa/secp256k1
*/
public class NativeSecp256k1 {
public static final boolean enabled;
static {
boolean isEnabled = true;
try {
System.loadLibrary("javasecp256k1");
} catch (UnsatisfiedLinkError e) {
isEnabled = false;
}
enabled = isEnabled;
}
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
/**
* Verifies the given secp256k1 signature in native code.
* Calling when enabled == false is undefined (probably library not loaded)
*
* @param data The data which was signed, must be exactly 32 bytes
* @param signature The signature
* @param pub The public key which did the signing
*/
public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null) {
byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(data);
byteBuff.putInt(signature.length);
byteBuff.putInt(pub.length);
byteBuff.put(signature);
byteBuff.put(pub);
return secp256k1_ecdsa_verify(byteBuff) == 1;
}
/**
* @param byteBuff signature format is byte[32] data,
* native-endian int signatureLength, native-endian int pubkeyLength,
* byte[signatureLength] signature, byte[pubkeyLength] pub
* @returns 1 for valid signature, anything else for invalid
*/
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
}

View File

@ -0,0 +1,23 @@
#include "org_bitcoin_NativeSecp256k1.h"
#include "include/secp256k1.h"
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
(JNIEnv* env, jclass classObject, jobject byteBufferObject)
{
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
int sigLen = *((int*)(data + 32));
int pubLen = *((int*)(data + 32 + 4));
return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen);
}
static void __javasecp256k1_attach(void) __attribute__((constructor));
static void __javasecp256k1_detach(void) __attribute__((destructor));
static void __javasecp256k1_attach(void) {
secp256k1_start();
}
static void __javasecp256k1_detach(void) {
secp256k1_stop();
}

View File

@ -0,0 +1,21 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_bitcoin_NativeSecp256k1 */
#ifndef _Included_org_bitcoin_NativeSecp256k1
#define _Included_org_bitcoin_NativeSecp256k1
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ecdsa_verify
* Signature: (Ljava/nio/ByteBuffer;)I
*/
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
(JNIEnv *, jclass, jobject);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,93 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_NUM_
#define _SECP256K1_NUM_
#if defined(USE_NUM_GMP)
#include "num_gmp.h"
#elif defined(USE_NUM_OPENSSL)
#include "num_openssl.h"
#else
#error "Please select num implementation"
#endif
/** Initialize a number. */
void static secp256k1_num_init(secp256k1_num_t *r);
/** Free a number. */
void static secp256k1_num_free(secp256k1_num_t *r);
/** Copy a number. */
void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a);
/** Convert a number's absolute value to a binary big-endian string.
* There must be enough place. */
void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a);
/** Set a number to the value of a binary big-endian string. */
void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen);
/** Set a number equal to a (signed) integer. */
void static secp256k1_num_set_int(secp256k1_num_t *r, int a);
/** Compute a modular inverse. The input must be less than the modulus. */
void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m);
/** Multiply two numbers modulo another. */
void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m);
/** Compare the absolute value of two numbers. */
int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b);
/** Add two (signed) numbers. */
void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
/** Subtract two (signed) numbers. */
void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
/** Multiply two (signed) numbers. */
void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
/** Divide two (signed) numbers. */
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1,
even if r was negative. */
void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m);
/** Calculate the number of bits in (the absolute value of) a number. */
int static secp256k1_num_bits(const secp256k1_num_t *a);
/** Right-shift the passed number by bits bits, and return those bits. */
int static secp256k1_num_shift(secp256k1_num_t *r, int bits);
/** Check whether a number is zero. */
int static secp256k1_num_is_zero(const secp256k1_num_t *a);
/** Check whether a number is odd. */
int static secp256k1_num_is_odd(const secp256k1_num_t *a);
/** Check whether a number is strictly negative. */
int static secp256k1_num_is_neg(const secp256k1_num_t *a);
/** Check whether a particular bit is set in a number. */
int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos);
/** Increase a number by 1. */
void static secp256k1_num_inc(secp256k1_num_t *r);
/** Set a number equal to the value of a hex string (unsigned). */
void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen);
/** Convert (the absolute value of) a number to a hexadecimal string. */
void static secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a);
/** Split a number into a low and high part. */
void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits);
/** Change a number's sign. */
void static secp256k1_num_negate(secp256k1_num_t *r);
#endif

View File

@ -0,0 +1,18 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_NUM_REPR_
#define _SECP256K1_NUM_REPR_
#include <gmp.h>
#define NUM_LIMBS ((256+GMP_NUMB_BITS-1)/GMP_NUMB_BITS)
typedef struct {
mp_limb_t data[2*NUM_LIMBS];
int neg;
int limbs;
} secp256k1_num_t;
#endif

View File

@ -0,0 +1,14 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_NUM_REPR_
#define _SECP256K1_NUM_REPR_
#include <openssl/bn.h>
typedef struct {
BIGNUM bn;
} secp256k1_num_t;
#endif

View File

@ -0,0 +1,269 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "impl/num.h"
#include "impl/field.h"
#include "impl/group.h"
#include "impl/ecmult.h"
#include "impl/ecdsa.h"
void secp256k1_start(void) {
secp256k1_fe_start();
secp256k1_ge_start();
secp256k1_ecmult_start();
}
void secp256k1_stop(void) {
secp256k1_ecmult_stop();
secp256k1_ge_stop();
secp256k1_fe_stop();
}
int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) {
int ret = -3;
secp256k1_num_t m;
secp256k1_num_init(&m);
secp256k1_ecdsa_sig_t s;
secp256k1_ecdsa_sig_init(&s);
secp256k1_ge_t q;
secp256k1_num_set_bin(&m, msg, msglen);
if (!secp256k1_ecdsa_pubkey_parse(&q, pubkey, pubkeylen)) {
ret = -1;
goto end;
}
if (!secp256k1_ecdsa_sig_parse(&s, sig, siglen)) {
ret = -2;
goto end;
}
if (!secp256k1_ecdsa_sig_verify(&s, &q, &m)) {
ret = 0;
goto end;
}
ret = 1;
end:
secp256k1_ecdsa_sig_free(&s);
secp256k1_num_free(&m);
return ret;
}
int secp256k1_ecdsa_sign(const unsigned char *message, int messagelen, unsigned char *signature, int *signaturelen, const unsigned char *seckey, const unsigned char *nonce) {
secp256k1_num_t sec, non, msg;
secp256k1_num_init(&sec);
secp256k1_num_init(&non);
secp256k1_num_init(&msg);
secp256k1_num_set_bin(&sec, seckey, 32);
secp256k1_num_set_bin(&non, nonce, 32);
secp256k1_num_set_bin(&msg, message, messagelen);
secp256k1_ecdsa_sig_t sig;
secp256k1_ecdsa_sig_init(&sig);
int ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, NULL);
if (ret) {
secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
}
secp256k1_ecdsa_sig_free(&sig);
secp256k1_num_free(&msg);
secp256k1_num_free(&non);
secp256k1_num_free(&sec);
return ret;
}
int secp256k1_ecdsa_sign_compact(const unsigned char *message, int messagelen, unsigned char *sig64, const unsigned char *seckey, const unsigned char *nonce, int *recid) {
secp256k1_num_t sec, non, msg;
secp256k1_num_init(&sec);
secp256k1_num_init(&non);
secp256k1_num_init(&msg);
secp256k1_num_set_bin(&sec, seckey, 32);
secp256k1_num_set_bin(&non, nonce, 32);
secp256k1_num_set_bin(&msg, message, messagelen);
secp256k1_ecdsa_sig_t sig;
secp256k1_ecdsa_sig_init(&sig);
int ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid);
if (ret) {
secp256k1_num_get_bin(sig64, 32, &sig.r);
secp256k1_num_get_bin(sig64 + 32, 32, &sig.s);
}
secp256k1_ecdsa_sig_free(&sig);
secp256k1_num_free(&msg);
secp256k1_num_free(&non);
secp256k1_num_free(&sec);
return ret;
}
int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) {
int ret = 0;
secp256k1_num_t m;
secp256k1_num_init(&m);
secp256k1_ecdsa_sig_t sig;
secp256k1_ecdsa_sig_init(&sig);
secp256k1_num_set_bin(&sig.r, sig64, 32);
secp256k1_num_set_bin(&sig.s, sig64 + 32, 32);
secp256k1_num_set_bin(&m, msg, msglen);
secp256k1_ge_t q;
if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) {
secp256k1_ecdsa_pubkey_serialize(&q, pubkey, pubkeylen, compressed);
ret = 1;
}
secp256k1_ecdsa_sig_free(&sig);
secp256k1_num_free(&m);
return ret;
}
int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey) {
secp256k1_num_t sec;
secp256k1_num_init(&sec);
secp256k1_num_set_bin(&sec, seckey, 32);
int ret = !secp256k1_num_is_zero(&sec) &&
(secp256k1_num_cmp(&sec, &secp256k1_ge_consts->order) < 0);
secp256k1_num_free(&sec);
return ret;
}
int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen) {
secp256k1_ge_t q;
return secp256k1_ecdsa_pubkey_parse(&q, pubkey, pubkeylen);
}
int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) {
secp256k1_num_t sec;
secp256k1_num_init(&sec);
secp256k1_num_set_bin(&sec, seckey, 32);
secp256k1_gej_t pj;
secp256k1_ecmult_gen(&pj, &sec);
secp256k1_ge_t p;
secp256k1_ge_set_gej(&p, &pj);
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, pubkeylen, compressed);
return 1;
}
int secp256k1_ecdsa_pubkey_decompress(unsigned char *pubkey, int *pubkeylen) {
secp256k1_ge_t p;
if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, *pubkeylen))
return 0;
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, pubkeylen, 0);
return 1;
}
int secp256k1_ecdsa_privkey_tweak_add(unsigned char *seckey, const unsigned char *tweak) {
int ret = 1;
secp256k1_num_t term;
secp256k1_num_init(&term);
secp256k1_num_set_bin(&term, tweak, 32);
if (secp256k1_num_cmp(&term, &secp256k1_ge_consts->order) >= 0)
ret = 0;
secp256k1_num_t sec;
secp256k1_num_init(&sec);
if (ret) {
secp256k1_num_set_bin(&sec, seckey, 32);
secp256k1_num_add(&sec, &sec, &term);
secp256k1_num_mod(&sec, &secp256k1_ge_consts->order);
if (secp256k1_num_is_zero(&sec))
ret = 0;
}
if (ret)
secp256k1_num_get_bin(seckey, 32, &sec);
secp256k1_num_free(&sec);
secp256k1_num_free(&term);
return ret;
}
int secp256k1_ecdsa_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
int ret = 1;
secp256k1_num_t term;
secp256k1_num_init(&term);
secp256k1_num_set_bin(&term, tweak, 32);
if (secp256k1_num_cmp(&term, &secp256k1_ge_consts->order) >= 0)
ret = 0;
secp256k1_ge_t p;
if (ret) {
if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, pubkeylen))
ret = 0;
}
if (ret) {
secp256k1_gej_t pt;
secp256k1_ecmult_gen(&pt, &term);
secp256k1_gej_add_ge(&pt, &pt, &p);
if (secp256k1_gej_is_infinity(&pt))
ret = 0;
secp256k1_ge_set_gej(&p, &pt);
int oldlen = pubkeylen;
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
assert(pubkeylen == oldlen);
}
secp256k1_num_free(&term);
return ret;
}
int secp256k1_ecdsa_privkey_tweak_mul(unsigned char *seckey, const unsigned char *tweak) {
int ret = 1;
secp256k1_num_t factor;
secp256k1_num_init(&factor);
secp256k1_num_set_bin(&factor, tweak, 32);
if (secp256k1_num_is_zero(&factor))
ret = 0;
if (secp256k1_num_cmp(&factor, &secp256k1_ge_consts->order) >= 0)
ret = 0;
secp256k1_num_t sec;
secp256k1_num_init(&sec);
if (ret) {
secp256k1_num_set_bin(&sec, seckey, 32);
secp256k1_num_mod_mul(&sec, &sec, &factor, &secp256k1_ge_consts->order);
}
if (ret)
secp256k1_num_get_bin(seckey, 32, &sec);
secp256k1_num_free(&sec);
secp256k1_num_free(&factor);
return ret;
}
int secp256k1_ecdsa_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
int ret = 1;
secp256k1_num_t factor;
secp256k1_num_init(&factor);
secp256k1_num_set_bin(&factor, tweak, 32);
if (secp256k1_num_is_zero(&factor))
ret = 0;
if (secp256k1_num_cmp(&factor, &secp256k1_ge_consts->order) >= 0)
ret = 0;
secp256k1_ge_t p;
if (ret) {
if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, pubkeylen))
ret = 0;
}
if (ret) {
secp256k1_num_t zero;
secp256k1_num_init(&zero);
secp256k1_num_set_int(&zero, 0);
secp256k1_gej_t pt;
secp256k1_gej_set_ge(&pt, &p);
secp256k1_ecmult(&pt, &pt, &factor, &zero);
secp256k1_num_free(&zero);
secp256k1_ge_set_gej(&p, &pt);
int oldlen = pubkeylen;
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
assert(pubkeylen == oldlen);
}
secp256k1_num_free(&factor);
return ret;
}
int secp256k1_ecdsa_privkey_export(const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) {
secp256k1_num_t key;
secp256k1_num_init(&key);
secp256k1_num_set_bin(&key, seckey, 32);
int ret = secp256k1_ecdsa_privkey_serialize(privkey, privkeylen, &key, compressed);
secp256k1_num_free(&key);
return ret;
}
int secp256k1_ecdsa_privkey_import(unsigned char *seckey, const unsigned char *privkey, int privkeylen) {
secp256k1_num_t key;
secp256k1_num_init(&key);
int ret = secp256k1_ecdsa_privkey_parse(&key, privkey, privkeylen);
if (ret)
secp256k1_num_get_bin(seckey, 32, &key);
secp256k1_num_free(&key);
return ret;
}

View File

@ -0,0 +1,465 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <assert.h>
#include "impl/num.h"
#include "impl/field.h"
#include "impl/group.h"
#include "impl/ecmult.h"
#include "impl/ecdsa.h"
#include "impl/util.h"
#ifdef ENABLE_OPENSSL_TESTS
#include "openssl/bn.h"
#include "openssl/ec.h"
#include "openssl/ecdsa.h"
#include "openssl/obj_mac.h"
#endif
static int count = 100;
/***** NUM TESTS *****/
void random_num_negate(secp256k1_num_t *num) {
if (secp256k1_rand32() & 1)
secp256k1_num_negate(num);
}
void random_num_order_test(secp256k1_num_t *num) {
do {
unsigned char b32[32];
secp256k1_rand256_test(b32);
secp256k1_num_set_bin(num, b32, 32);
if (secp256k1_num_is_zero(num))
continue;
if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
continue;
break;
} while(1);
}
void random_num_order(secp256k1_num_t *num) {
do {
unsigned char b32[32];
secp256k1_rand256(b32);
secp256k1_num_set_bin(num, b32, 32);
if (secp256k1_num_is_zero(num))
continue;
if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
continue;
break;
} while(1);
}
void test_num_copy_inc_cmp() {
secp256k1_num_t n1,n2;
secp256k1_num_init(&n1);
secp256k1_num_init(&n2);
random_num_order(&n1);
secp256k1_num_copy(&n2, &n1);
assert(secp256k1_num_cmp(&n1, &n2) == 0);
assert(secp256k1_num_cmp(&n2, &n1) == 0);
secp256k1_num_inc(&n2);
assert(secp256k1_num_cmp(&n1, &n2) != 0);
assert(secp256k1_num_cmp(&n2, &n1) != 0);
secp256k1_num_free(&n1);
secp256k1_num_free(&n2);
}
void test_num_get_set_hex() {
secp256k1_num_t n1,n2;
secp256k1_num_init(&n1);
secp256k1_num_init(&n2);
random_num_order_test(&n1);
char c[64];
secp256k1_num_get_hex(c, 64, &n1);
secp256k1_num_set_hex(&n2, c, 64);
assert(secp256k1_num_cmp(&n1, &n2) == 0);
for (int i=0; i<64; i++) {
// check whether the lower 4 bits correspond to the last hex character
int low1 = secp256k1_num_shift(&n1, 4);
int lowh = c[63];
int low2 = (lowh>>6)*9+(lowh-'0')&15;
assert(low1 == low2);
// shift bits off the hex representation, and compare
memmove(c+1, c, 63);
c[0] = '0';
secp256k1_num_set_hex(&n2, c, 64);
assert(secp256k1_num_cmp(&n1, &n2) == 0);
}
secp256k1_num_free(&n2);
secp256k1_num_free(&n1);
}
void test_num_get_set_bin() {
secp256k1_num_t n1,n2;
secp256k1_num_init(&n1);
secp256k1_num_init(&n2);
random_num_order_test(&n1);
unsigned char c[32];
secp256k1_num_get_bin(c, 32, &n1);
secp256k1_num_set_bin(&n2, c, 32);
assert(secp256k1_num_cmp(&n1, &n2) == 0);
for (int i=0; i<32; i++) {
// check whether the lower 8 bits correspond to the last byte
int low1 = secp256k1_num_shift(&n1, 8);
int low2 = c[31];
assert(low1 == low2);
// shift bits off the byte representation, and compare
memmove(c+1, c, 31);
c[0] = 0;
secp256k1_num_set_bin(&n2, c, 32);
assert(secp256k1_num_cmp(&n1, &n2) == 0);
}
secp256k1_num_free(&n2);
secp256k1_num_free(&n1);
}
void run_num_int() {
secp256k1_num_t n1;
secp256k1_num_init(&n1);
for (int i=-255; i<256; i++) {
unsigned char c1[3] = {};
c1[2] = abs(i);
unsigned char c2[3] = {0x11,0x22,0x33};
secp256k1_num_set_int(&n1, i);
secp256k1_num_get_bin(c2, 3, &n1);
assert(memcmp(c1, c2, 3) == 0);
}
secp256k1_num_free(&n1);
}
void test_num_negate() {
secp256k1_num_t n1;
secp256k1_num_t n2;
secp256k1_num_init(&n1);
secp256k1_num_init(&n2);
random_num_order_test(&n1); // n1 = R
random_num_negate(&n1);
secp256k1_num_copy(&n2, &n1); // n2 = R
secp256k1_num_sub(&n1, &n2, &n1); // n1 = n2-n1 = 0
assert(secp256k1_num_is_zero(&n1));
secp256k1_num_copy(&n1, &n2); // n1 = R
secp256k1_num_negate(&n1); // n1 = -R
assert(!secp256k1_num_is_zero(&n1));
secp256k1_num_add(&n1, &n2, &n1); // n1 = n2+n1 = 0
assert(secp256k1_num_is_zero(&n1));
secp256k1_num_copy(&n1, &n2); // n1 = R
secp256k1_num_negate(&n1); // n1 = -R
assert(secp256k1_num_is_neg(&n1) != secp256k1_num_is_neg(&n2));
secp256k1_num_negate(&n1); // n1 = R
assert(secp256k1_num_cmp(&n1, &n2) == 0);
assert(secp256k1_num_is_neg(&n1) == secp256k1_num_is_neg(&n2));
secp256k1_num_free(&n2);
secp256k1_num_free(&n1);
}
void test_num_add_sub() {
secp256k1_num_t n1;
secp256k1_num_t n2;
secp256k1_num_init(&n1);
secp256k1_num_init(&n2);
random_num_order_test(&n1); // n1 = R1
random_num_negate(&n1);
random_num_order_test(&n2); // n2 = R2
random_num_negate(&n2);
secp256k1_num_t n1p2, n2p1, n1m2, n2m1;
secp256k1_num_init(&n1p2);
secp256k1_num_init(&n2p1);
secp256k1_num_init(&n1m2);
secp256k1_num_init(&n2m1);
secp256k1_num_add(&n1p2, &n1, &n2); // n1p2 = R1 + R2
secp256k1_num_add(&n2p1, &n2, &n1); // n2p1 = R2 + R1
secp256k1_num_sub(&n1m2, &n1, &n2); // n1m2 = R1 - R2
secp256k1_num_sub(&n2m1, &n2, &n1); // n2m1 = R2 - R1
assert(secp256k1_num_cmp(&n1p2, &n2p1) == 0);
assert(secp256k1_num_cmp(&n1p2, &n1m2) != 0);
secp256k1_num_negate(&n2m1); // n2m1 = -R2 + R1
assert(secp256k1_num_cmp(&n2m1, &n1m2) == 0);
assert(secp256k1_num_cmp(&n2m1, &n1) != 0);
secp256k1_num_add(&n2m1, &n2m1, &n2); // n2m1 = -R2 + R1 + R2 = R1
assert(secp256k1_num_cmp(&n2m1, &n1) == 0);
assert(secp256k1_num_cmp(&n2p1, &n1) != 0);
secp256k1_num_sub(&n2p1, &n2p1, &n2); // n2p1 = R2 + R1 - R2 = R1
assert(secp256k1_num_cmp(&n2p1, &n1) == 0);
secp256k1_num_free(&n2m1);
secp256k1_num_free(&n1m2);
secp256k1_num_free(&n2p1);
secp256k1_num_free(&n1p2);
secp256k1_num_free(&n2);
secp256k1_num_free(&n1);
}
void run_num_smalltests() {
for (int i=0; i<100*count; i++) {
test_num_copy_inc_cmp();
test_num_get_set_hex();
test_num_get_set_bin();
test_num_negate();
test_num_add_sub();
}
run_num_int();
}
void run_ecmult_chain() {
// random starting point A (on the curve)
secp256k1_fe_t ax; secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64);
secp256k1_fe_t ay; secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
secp256k1_gej_t a; secp256k1_gej_set_xy(&a, &ax, &ay);
// two random initial factors xn and gn
secp256k1_num_t xn;
secp256k1_num_init(&xn);
secp256k1_num_set_hex(&xn, "84cc5452f7fde1edb4d38a8ce9b1b84ccef31f146e569be9705d357a42985407", 64);
secp256k1_num_t gn;
secp256k1_num_init(&gn);
secp256k1_num_set_hex(&gn, "a1e58d22553dcd42b23980625d4c57a96e9323d42b3152e5ca2c3990edc7c9de", 64);
// two small multipliers to be applied to xn and gn in every iteration:
secp256k1_num_t xf;
secp256k1_num_init(&xf);
secp256k1_num_set_hex(&xf, "1337", 4);
secp256k1_num_t gf;
secp256k1_num_init(&gf);
secp256k1_num_set_hex(&gf, "7113", 4);
// accumulators with the resulting coefficients to A and G
secp256k1_num_t ae;
secp256k1_num_init(&ae);
secp256k1_num_set_int(&ae, 1);
secp256k1_num_t ge;
secp256k1_num_init(&ge);
secp256k1_num_set_int(&ge, 0);
// the point being computed
secp256k1_gej_t x = a;
const secp256k1_num_t *order = &secp256k1_ge_consts->order;
for (int i=0; i<200*count; i++) {
// in each iteration, compute X = xn*X + gn*G;
secp256k1_ecmult(&x, &x, &xn, &gn);
// also compute ae and ge: the actual accumulated factors for A and G
// if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G)
secp256k1_num_mod_mul(&ae, &ae, &xn, order);
secp256k1_num_mod_mul(&ge, &ge, &xn, order);
secp256k1_num_add(&ge, &ge, &gn);
secp256k1_num_mod(&ge, order);
// modify xn and gn
secp256k1_num_mod_mul(&xn, &xn, &xf, order);
secp256k1_num_mod_mul(&gn, &gn, &gf, order);
// verify
if (i == 19999) {
char res[132]; int resl = 132;
secp256k1_gej_get_hex(res, &resl, &x);
assert(strcmp(res, "(D6E96687F9B10D092A6F35439D86CEBEA4535D0D409F53586440BD74B933E830,B95CBCA2C77DA786539BE8FD53354D2D3B4F566AE658045407ED6015EE1B2A88)") == 0);
}
}
// redo the computation, but directly with the resulting ae and ge coefficients:
secp256k1_gej_t x2; secp256k1_ecmult(&x2, &a, &ae, &ge);
char res[132]; int resl = 132;
char res2[132]; int resl2 = 132;
secp256k1_gej_get_hex(res, &resl, &x);
secp256k1_gej_get_hex(res2, &resl2, &x2);
assert(strcmp(res, res2) == 0);
assert(strlen(res) == 131);
secp256k1_num_free(&xn);
secp256k1_num_free(&gn);
secp256k1_num_free(&xf);
secp256k1_num_free(&gf);
secp256k1_num_free(&ae);
secp256k1_num_free(&ge);
}
void test_point_times_order(const secp256k1_gej_t *point) {
// either the point is not on the curve, or multiplying it by the order results in O
if (!secp256k1_gej_is_valid(point))
return;
const secp256k1_num_t *order = &secp256k1_ge_consts->order;
secp256k1_num_t zero;
secp256k1_num_init(&zero);
secp256k1_num_set_int(&zero, 0);
secp256k1_gej_t res;
secp256k1_ecmult(&res, point, order, order); // calc res = order * point + order * G;
assert(secp256k1_gej_is_infinity(&res));
secp256k1_num_free(&zero);
}
void run_point_times_order() {
secp256k1_fe_t x; secp256k1_fe_set_hex(&x, "02", 2);
for (int i=0; i<500; i++) {
secp256k1_ge_t p; secp256k1_ge_set_xo(&p, &x, 1);
secp256k1_gej_t j; secp256k1_gej_set_ge(&j, &p);
test_point_times_order(&j);
secp256k1_fe_sqr(&x, &x);
}
char c[65]; int cl=65;
secp256k1_fe_get_hex(c, &cl, &x);
assert(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0);
}
void test_wnaf(const secp256k1_num_t *number, int w) {
secp256k1_num_t x, two, t;
secp256k1_num_init(&x);
secp256k1_num_init(&two);
secp256k1_num_init(&t);
secp256k1_num_set_int(&x, 0);
secp256k1_num_set_int(&two, 2);
int wnaf[257];
int bits = secp256k1_ecmult_wnaf(wnaf, number, w);
int zeroes = -1;
for (int i=bits-1; i>=0; i--) {
secp256k1_num_mul(&x, &x, &two);
int v = wnaf[i];
if (v) {
assert(zeroes == -1 || zeroes >= w-1); // check that distance between non-zero elements is at least w-1
zeroes=0;
assert((v & 1) == 1); // check non-zero elements are odd
assert(v <= (1 << (w-1)) - 1); // check range below
assert(v >= -(1 << (w-1)) - 1); // check range above
} else {
assert(zeroes != -1); // check that no unnecessary zero padding exists
zeroes++;
}
secp256k1_num_set_int(&t, v);
secp256k1_num_add(&x, &x, &t);
}
assert(secp256k1_num_cmp(&x, number) == 0); // check that wnaf represents number
secp256k1_num_free(&x);
secp256k1_num_free(&two);
secp256k1_num_free(&t);
}
void run_wnaf() {
secp256k1_num_t n;
secp256k1_num_init(&n);
for (int i=0; i<count; i++) {
random_num_order(&n);
if (i % 1)
secp256k1_num_negate(&n);
test_wnaf(&n, 4+(i%10));
}
secp256k1_num_free(&n);
}
void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *key, const secp256k1_num_t *msg, int *recid) {
secp256k1_num_t nonce;
secp256k1_num_init(&nonce);
do {
random_num_order_test(&nonce);
} while(!secp256k1_ecdsa_sig_sign(sig, key, msg, &nonce, recid));
secp256k1_num_free(&nonce);
}
void test_ecdsa_sign_verify() {
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
secp256k1_num_t msg, key;
secp256k1_num_init(&msg);
random_num_order_test(&msg);
secp256k1_num_init(&key);
random_num_order_test(&key);
secp256k1_gej_t pubj; secp256k1_ecmult_gen(&pubj, &key);
secp256k1_ge_t pub; secp256k1_ge_set_gej(&pub, &pubj);
secp256k1_ecdsa_sig_t sig;
secp256k1_ecdsa_sig_init(&sig);
random_sign(&sig, &key, &msg, NULL);
assert(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
secp256k1_num_inc(&msg);
assert(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
secp256k1_ecdsa_sig_free(&sig);
secp256k1_num_free(&msg);
secp256k1_num_free(&key);
}
void run_ecdsa_sign_verify() {
for (int i=0; i<10*count; i++) {
test_ecdsa_sign_verify();
}
}
#ifdef ENABLE_OPENSSL_TESTS
EC_KEY *get_openssl_key(const secp256k1_num_t *key) {
unsigned char privkey[300];
int privkeylen;
int compr = secp256k1_rand32() & 1;
const unsigned char* pbegin = privkey;
EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
assert(secp256k1_ecdsa_privkey_serialize(privkey, &privkeylen, key, compr));
assert(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen));
assert(EC_KEY_check_key(ec_key));
return ec_key;
}
void test_ecdsa_openssl() {
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
secp256k1_num_t key, msg;
secp256k1_num_init(&msg);
unsigned char message[32];
secp256k1_rand256_test(message);
secp256k1_num_set_bin(&msg, message, 32);
secp256k1_num_init(&key);
random_num_order_test(&key);
secp256k1_gej_t qj;
secp256k1_ecmult_gen(&qj, &key);
secp256k1_ge_t q;
secp256k1_ge_set_gej(&q, &qj);
EC_KEY *ec_key = get_openssl_key(&key);
assert(ec_key);
unsigned char signature[80];
int sigsize = 80;
assert(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key));
secp256k1_ecdsa_sig_t sig;
secp256k1_ecdsa_sig_init(&sig);
assert(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize));
assert(secp256k1_ecdsa_sig_verify(&sig, &q, &msg));
secp256k1_num_inc(&sig.r);
assert(!secp256k1_ecdsa_sig_verify(&sig, &q, &msg));
random_sign(&sig, &key, &msg, NULL);
sigsize = 80;
assert(secp256k1_ecdsa_sig_serialize(signature, &sigsize, &sig));
assert(ECDSA_verify(0, message, sizeof(message), signature, sigsize, ec_key) == 1);
secp256k1_ecdsa_sig_free(&sig);
EC_KEY_free(ec_key);
secp256k1_num_free(&key);
secp256k1_num_free(&msg);
}
void run_ecdsa_openssl() {
for (int i=0; i<10*count; i++) {
test_ecdsa_openssl();
}
}
#endif
int main(int argc, char **argv) {
if (argc > 1)
count = strtol(argv[1], NULL, 0)*47;
printf("test count = %i\n", count);
// initialize
secp256k1_fe_start();
secp256k1_ge_start();
secp256k1_ecmult_start();
// num tests
run_num_smalltests();
// ecmult tests
run_wnaf();
run_point_times_order();
run_ecmult_chain();
// ecdsa tests
run_ecdsa_sign_verify();
#ifdef ENABLE_OPENSSL_TESTS
run_ecdsa_openssl();
#endif
// shutdown
secp256k1_ecmult_stop();
secp256k1_ge_stop();
secp256k1_fe_stop();
return 0;
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_UTIL_H_
#define _SECP256K1_UTIL_H_
/** Generate a pseudorandom 32-bit number. */
static uint32_t secp256k1_rand32(void);
/** Generate a pseudorandom 32-byte array. */
static void secp256k1_rand256(unsigned char *b32);
/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */
static void secp256k1_rand256_test(unsigned char *b32);
#include "impl/util.h"
#endif

171
crypto/sha3/keccakf.go Normal file
View File

@ -0,0 +1,171 @@
// 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 sha3
// This file implements the core Keccak permutation function necessary for computing SHA3.
// This is implemented in a separate file to allow for replacement by an optimized implementation.
// Nothing in this package is exported.
// For the detailed specification, refer to the Keccak web site (http://keccak.noekeon.org/).
// rc stores the round constants for use in the ι step.
var rc = [...]uint64{
0x0000000000000001,
0x0000000000008082,
0x800000000000808A,
0x8000000080008000,
0x000000000000808B,
0x0000000080000001,
0x8000000080008081,
0x8000000000008009,
0x000000000000008A,
0x0000000000000088,
0x0000000080008009,
0x000000008000000A,
0x000000008000808B,
0x800000000000008B,
0x8000000000008089,
0x8000000000008003,
0x8000000000008002,
0x8000000000000080,
0x000000000000800A,
0x800000008000000A,
0x8000000080008081,
0x8000000000008080,
0x0000000080000001,
0x8000000080008008,
}
// ro_xx represent the rotation offsets for use in the χ step.
// Defining them as const instead of in an array allows the compiler to insert constant shifts.
const (
ro_00 = 0
ro_01 = 36
ro_02 = 3
ro_03 = 41
ro_04 = 18
ro_05 = 1
ro_06 = 44
ro_07 = 10
ro_08 = 45
ro_09 = 2
ro_10 = 62
ro_11 = 6
ro_12 = 43
ro_13 = 15
ro_14 = 61
ro_15 = 28
ro_16 = 55
ro_17 = 25
ro_18 = 21
ro_19 = 56
ro_20 = 27
ro_21 = 20
ro_22 = 39
ro_23 = 8
ro_24 = 14
)
// keccakF computes the complete Keccak-f function consisting of 24 rounds with a different
// constant (rc) in each round. This implementation fully unrolls the round function to avoid
// inner loops, as well as pre-calculating shift offsets.
func (d *digest) keccakF() {
for _, roundConstant := range rc {
// θ step
d.c[0] = d.a[0] ^ d.a[5] ^ d.a[10] ^ d.a[15] ^ d.a[20]
d.c[1] = d.a[1] ^ d.a[6] ^ d.a[11] ^ d.a[16] ^ d.a[21]
d.c[2] = d.a[2] ^ d.a[7] ^ d.a[12] ^ d.a[17] ^ d.a[22]
d.c[3] = d.a[3] ^ d.a[8] ^ d.a[13] ^ d.a[18] ^ d.a[23]
d.c[4] = d.a[4] ^ d.a[9] ^ d.a[14] ^ d.a[19] ^ d.a[24]
d.d[0] = d.c[4] ^ (d.c[1]<<1 ^ d.c[1]>>63)
d.d[1] = d.c[0] ^ (d.c[2]<<1 ^ d.c[2]>>63)
d.d[2] = d.c[1] ^ (d.c[3]<<1 ^ d.c[3]>>63)
d.d[3] = d.c[2] ^ (d.c[4]<<1 ^ d.c[4]>>63)
d.d[4] = d.c[3] ^ (d.c[0]<<1 ^ d.c[0]>>63)
d.a[0] ^= d.d[0]
d.a[1] ^= d.d[1]
d.a[2] ^= d.d[2]
d.a[3] ^= d.d[3]
d.a[4] ^= d.d[4]
d.a[5] ^= d.d[0]
d.a[6] ^= d.d[1]
d.a[7] ^= d.d[2]
d.a[8] ^= d.d[3]
d.a[9] ^= d.d[4]
d.a[10] ^= d.d[0]
d.a[11] ^= d.d[1]
d.a[12] ^= d.d[2]
d.a[13] ^= d.d[3]
d.a[14] ^= d.d[4]
d.a[15] ^= d.d[0]
d.a[16] ^= d.d[1]
d.a[17] ^= d.d[2]
d.a[18] ^= d.d[3]
d.a[19] ^= d.d[4]
d.a[20] ^= d.d[0]
d.a[21] ^= d.d[1]
d.a[22] ^= d.d[2]
d.a[23] ^= d.d[3]
d.a[24] ^= d.d[4]
// ρ and π steps
d.b[0] = d.a[0]
d.b[1] = d.a[6]<<ro_06 ^ d.a[6]>>(64-ro_06)
d.b[2] = d.a[12]<<ro_12 ^ d.a[12]>>(64-ro_12)
d.b[3] = d.a[18]<<ro_18 ^ d.a[18]>>(64-ro_18)
d.b[4] = d.a[24]<<ro_24 ^ d.a[24]>>(64-ro_24)
d.b[5] = d.a[3]<<ro_15 ^ d.a[3]>>(64-ro_15)
d.b[6] = d.a[9]<<ro_21 ^ d.a[9]>>(64-ro_21)
d.b[7] = d.a[10]<<ro_02 ^ d.a[10]>>(64-ro_02)
d.b[8] = d.a[16]<<ro_08 ^ d.a[16]>>(64-ro_08)
d.b[9] = d.a[22]<<ro_14 ^ d.a[22]>>(64-ro_14)
d.b[10] = d.a[1]<<ro_05 ^ d.a[1]>>(64-ro_05)
d.b[11] = d.a[7]<<ro_11 ^ d.a[7]>>(64-ro_11)
d.b[12] = d.a[13]<<ro_17 ^ d.a[13]>>(64-ro_17)
d.b[13] = d.a[19]<<ro_23 ^ d.a[19]>>(64-ro_23)
d.b[14] = d.a[20]<<ro_04 ^ d.a[20]>>(64-ro_04)
d.b[15] = d.a[4]<<ro_20 ^ d.a[4]>>(64-ro_20)
d.b[16] = d.a[5]<<ro_01 ^ d.a[5]>>(64-ro_01)
d.b[17] = d.a[11]<<ro_07 ^ d.a[11]>>(64-ro_07)
d.b[18] = d.a[17]<<ro_13 ^ d.a[17]>>(64-ro_13)
d.b[19] = d.a[23]<<ro_19 ^ d.a[23]>>(64-ro_19)
d.b[20] = d.a[2]<<ro_10 ^ d.a[2]>>(64-ro_10)
d.b[21] = d.a[8]<<ro_16 ^ d.a[8]>>(64-ro_16)
d.b[22] = d.a[14]<<ro_22 ^ d.a[14]>>(64-ro_22)
d.b[23] = d.a[15]<<ro_03 ^ d.a[15]>>(64-ro_03)
d.b[24] = d.a[21]<<ro_09 ^ d.a[21]>>(64-ro_09)
// χ step
d.a[0] = d.b[0] ^ (^d.b[1] & d.b[2])
d.a[1] = d.b[1] ^ (^d.b[2] & d.b[3])
d.a[2] = d.b[2] ^ (^d.b[3] & d.b[4])
d.a[3] = d.b[3] ^ (^d.b[4] & d.b[0])
d.a[4] = d.b[4] ^ (^d.b[0] & d.b[1])
d.a[5] = d.b[5] ^ (^d.b[6] & d.b[7])
d.a[6] = d.b[6] ^ (^d.b[7] & d.b[8])
d.a[7] = d.b[7] ^ (^d.b[8] & d.b[9])
d.a[8] = d.b[8] ^ (^d.b[9] & d.b[5])
d.a[9] = d.b[9] ^ (^d.b[5] & d.b[6])
d.a[10] = d.b[10] ^ (^d.b[11] & d.b[12])
d.a[11] = d.b[11] ^ (^d.b[12] & d.b[13])
d.a[12] = d.b[12] ^ (^d.b[13] & d.b[14])
d.a[13] = d.b[13] ^ (^d.b[14] & d.b[10])
d.a[14] = d.b[14] ^ (^d.b[10] & d.b[11])
d.a[15] = d.b[15] ^ (^d.b[16] & d.b[17])
d.a[16] = d.b[16] ^ (^d.b[17] & d.b[18])
d.a[17] = d.b[17] ^ (^d.b[18] & d.b[19])
d.a[18] = d.b[18] ^ (^d.b[19] & d.b[15])
d.a[19] = d.b[19] ^ (^d.b[15] & d.b[16])
d.a[20] = d.b[20] ^ (^d.b[21] & d.b[22])
d.a[21] = d.b[21] ^ (^d.b[22] & d.b[23])
d.a[22] = d.b[22] ^ (^d.b[23] & d.b[24])
d.a[23] = d.b[23] ^ (^d.b[24] & d.b[20])
d.a[24] = d.b[24] ^ (^d.b[20] & d.b[21])
// ι step
d.a[0] ^= roundConstant
}
}

216
crypto/sha3/sha3.go Normal file
View File

@ -0,0 +1,216 @@
// 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 sha3 implements the SHA3 hash algorithm (formerly called Keccak) chosen by NIST in 2012.
// This file provides a SHA3 implementation which implements the standard hash.Hash interface.
// Writing input data, including padding, and reading output data are computed in this file.
// Note that the current implementation can compute the hash of an integral number of bytes only.
// This is a consequence of the hash interface in which a buffer of bytes is passed in.
// The internals of the Keccak-f function are computed in keccakf.go.
// For the detailed specification, refer to the Keccak web site (http://keccak.noekeon.org/).
package sha3
import (
"encoding/binary"
"hash"
)
// laneSize is the size in bytes of each "lane" of the internal state of SHA3 (5 * 5 * 8).
// Note that changing this size would requires using a type other than uint64 to store each lane.
const laneSize = 8
// sliceSize represents the dimensions of the internal state, a square matrix of
// sliceSize ** 2 lanes. This is the size of both the "rows" and "columns" dimensions in the
// terminology of the SHA3 specification.
const sliceSize = 5
// numLanes represents the total number of lanes in the state.
const numLanes = sliceSize * sliceSize
// stateSize is the size in bytes of the internal state of SHA3 (5 * 5 * WSize).
const stateSize = laneSize * numLanes
// digest represents the partial evaluation of a checksum.
// Note that capacity, and not outputSize, is the critical security parameter, as SHA3 can output
// an arbitrary number of bytes for any given capacity. The Keccak proposal recommends that
// capacity = 2*outputSize to ensure that finding a collision of size outputSize requires
// O(2^{outputSize/2}) computations (the birthday lower bound). Future standards may modify the
// capacity/outputSize ratio to allow for more output with lower cryptographic security.
type digest struct {
a [numLanes]uint64 // main state of the hash
b [numLanes]uint64 // intermediate states
c [sliceSize]uint64 // intermediate states
d [sliceSize]uint64 // intermediate states
outputSize int // desired output size in bytes
capacity int // number of bytes to leave untouched during squeeze/absorb
absorbed int // number of bytes absorbed thus far
}
// minInt returns the lesser of two integer arguments, to simplify the absorption routine.
func minInt(v1, v2 int) int {
if v1 <= v2 {
return v1
}
return v2
}
// rate returns the number of bytes of the internal state which can be absorbed or squeezed
// in between calls to the permutation function.
func (d *digest) rate() int {
return stateSize - d.capacity
}
// Reset clears the internal state by zeroing bytes in the state buffer.
// This can be skipped for a newly-created hash state; the default zero-allocated state is correct.
func (d *digest) Reset() {
d.absorbed = 0
for i := range d.a {
d.a[i] = 0
}
}
// BlockSize, required by the hash.Hash interface, does not have a standard intepretation
// for a sponge-based construction like SHA3. We return the data rate: the number of bytes which
// can be absorbed per invocation of the permutation function. For Merkle-Damgård based hashes
// (ie SHA1, SHA2, MD5) the output size of the internal compression function is returned.
// We consider this to be roughly equivalent because it represents the number of bytes of output
// produced per cryptographic operation.
func (d *digest) BlockSize() int { return d.rate() }
// Size returns the output size of the hash function in bytes.
func (d *digest) Size() int {
return d.outputSize
}
// unalignedAbsorb is a helper function for Write, which absorbs data that isn't aligned with an
// 8-byte lane. This requires shifting the individual bytes into position in a uint64.
func (d *digest) unalignedAbsorb(p []byte) {
var t uint64
for i := len(p) - 1; i >= 0; i-- {
t <<= 8
t |= uint64(p[i])
}
offset := (d.absorbed) % d.rate()
t <<= 8 * uint(offset%laneSize)
d.a[offset/laneSize] ^= t
d.absorbed += len(p)
}
// Write "absorbs" bytes into the state of the SHA3 hash, updating as needed when the sponge
// "fills up" with rate() bytes. Since lanes are stored internally as type uint64, this requires
// converting the incoming bytes into uint64s using a little endian interpretation. This
// implementation is optimized for large, aligned writes of multiples of 8 bytes (laneSize).
// Non-aligned or uneven numbers of bytes require shifting and are slower.
func (d *digest) Write(p []byte) (int, error) {
// An initial offset is needed if the we aren't absorbing to the first lane initially.
offset := d.absorbed % d.rate()
toWrite := len(p)
// The first lane may need to absorb unaligned and/or incomplete data.
if (offset%laneSize != 0 || len(p) < 8) && len(p) > 0 {
toAbsorb := minInt(laneSize-(offset%laneSize), len(p))
d.unalignedAbsorb(p[:toAbsorb])
p = p[toAbsorb:]
offset = (d.absorbed) % d.rate()
// For every rate() bytes absorbed, the state must be permuted via the F Function.
if (d.absorbed)%d.rate() == 0 {
d.keccakF()
}
}
// This loop should absorb the bulk of the data into full, aligned lanes.
// It will call the update function as necessary.
for len(p) > 7 {
firstLane := offset / laneSize
lastLane := minInt(d.rate()/laneSize, firstLane+len(p)/laneSize)
// This inner loop absorbs input bytes into the state in groups of 8, converted to uint64s.
for lane := firstLane; lane < lastLane; lane++ {
d.a[lane] ^= binary.LittleEndian.Uint64(p[:laneSize])
p = p[laneSize:]
}
d.absorbed += (lastLane - firstLane) * laneSize
// For every rate() bytes absorbed, the state must be permuted via the F Function.
if (d.absorbed)%d.rate() == 0 {
d.keccakF()
}
offset = 0
}
// If there are insufficient bytes to fill the final lane, an unaligned absorption.
// This should always start at a correct lane boundary though, or else it would be caught
// by the uneven opening lane case above.
if len(p) > 0 {
d.unalignedAbsorb(p)
}
return toWrite, nil
}
// pad computes the SHA3 padding scheme based on the number of bytes absorbed.
// The padding is a 1 bit, followed by an arbitrary number of 0s and then a final 1 bit, such that
// the input bits plus padding bits are a multiple of rate(). Adding the padding simply requires
// xoring an opening and closing bit into the appropriate lanes.
func (d *digest) pad() {
offset := d.absorbed % d.rate()
// The opening pad bit must be shifted into position based on the number of bytes absorbed
padOpenLane := offset / laneSize
d.a[padOpenLane] ^= 0x0000000000000001 << uint(8*(offset%laneSize))
// The closing padding bit is always in the last position
padCloseLane := (d.rate() / laneSize) - 1
d.a[padCloseLane] ^= 0x8000000000000000
}
// finalize prepares the hash to output data by padding and one final permutation of the state.
func (d *digest) finalize() {
d.pad()
d.keccakF()
}
// squeeze outputs an arbitrary number of bytes from the hash state.
// Squeezing can require multiple calls to the F function (one per rate() bytes squeezed),
// although this is not the case for standard SHA3 parameters. This implementation only supports
// squeezing a single time, subsequent squeezes may lose alignment. Future implementations
// may wish to support multiple squeeze calls, for example to support use as a PRNG.
func (d *digest) squeeze(in []byte, toSqueeze int) []byte {
// Because we read in blocks of laneSize, we need enough room to read
// an integral number of lanes
needed := toSqueeze + (laneSize-toSqueeze%laneSize)%laneSize
if cap(in)-len(in) < needed {
newIn := make([]byte, len(in), len(in)+needed)
copy(newIn, in)
in = newIn
}
out := in[len(in) : len(in)+needed]
for len(out) > 0 {
for i := 0; i < d.rate() && len(out) > 0; i += laneSize {
binary.LittleEndian.PutUint64(out[:], d.a[i/laneSize])
out = out[laneSize:]
}
if len(out) > 0 {
d.keccakF()
}
}
return in[:len(in)+toSqueeze] // Re-slice in case we wrote extra data.
}
// Sum applies padding to the hash state and then squeezes out the desired nubmer of output bytes.
func (d *digest) Sum(in []byte) []byte {
// Make a copy of the original hash so that caller can keep writing and summing.
dup := *d
dup.finalize()
return dup.squeeze(in, dup.outputSize)
}
// The NewKeccakX constructors enable initializing a hash in any of the four recommend sizes
// from the Keccak specification, all of which set capacity=2*outputSize. Note that the final
// NIST standard for SHA3 may specify different input/output lengths.
// The output size is indicated in bits but converted into bytes internally.
func NewKeccak224() hash.Hash { return &digest{outputSize: 224 / 8, capacity: 2 * 224 / 8} }
func NewKeccak256() hash.Hash { return &digest{outputSize: 256 / 8, capacity: 2 * 256 / 8} }
func NewKeccak384() hash.Hash { return &digest{outputSize: 384 / 8, capacity: 2 * 384 / 8} }
func NewKeccak512() hash.Hash { return &digest{outputSize: 512 / 8, capacity: 2 * 512 / 8} }

View File

@ -8,9 +8,9 @@ import (
"net" "net"
"os" "os"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/obscuren/secp256k1-go"
) )
func main() { func main() {

View File

@ -6,9 +6,9 @@ import (
"math/rand" "math/rand"
"time" "time"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/obscuren/sha3"
) )
var powlogger = logger.NewLogger("POW") var powlogger = logger.NewLogger("POW")

View File

@ -6,10 +6,10 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"github.com/obscuren/sha3"
) )
var powlogger = logger.NewLogger("POW") var powlogger = logger.NewLogger("POW")

4
tests/files/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
venv/
*~
*.swp
.vagrant/

View File

@ -0,0 +1,53 @@
{
"randomVMtest" : {
"callcreates" : [
],
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentGasLimit" : "1000000",
"currentNumber" : "300",
"currentTimestamp" : "2",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"code" : "0x4142414131424043923a58f2",
"data" : "0x",
"gas" : "10000",
"gasPrice" : "100000000000000",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000"
},
"gas" : "9940",
"logs" : [
],
"out" : "0x",
"post" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "0x4142414131424043923a58f2",
"nonce" : "0",
"storage" : {
}
},
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
"balance" : "0",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "0x4142414131424043923a58f2",
"nonce" : "0",
"storage" : {
}
}
}
}
}

View File

@ -0,0 +1,31 @@
{
"randomVMtest" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentGasLimit" : "1000000",
"currentNumber" : "300",
"currentTimestamp" : "2",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"code" : "0x4243434440448143f2a231f1",
"data" : "0x",
"gas" : "10000",
"gasPrice" : "100000000000000",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "0x4243434440448143f2a231f1",
"nonce" : "0",
"storage" : {
}
}
}
}
}

View File

@ -0,0 +1,31 @@
{
"randomVMtest" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentGasLimit" : "1000000",
"currentNumber" : "300",
"currentTimestamp" : "2",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"code" : "0x4243434244444340f201186211907055",
"data" : "0x",
"gas" : "10000",
"gasPrice" : "100000000000000",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "0x4243434244444340f201186211907055",
"nonce" : "0",
"storage" : {
}
}
}
}
}

View File

@ -0,0 +1,31 @@
{
"randomVMtest" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"currentGasLimit" : "1000000",
"currentNumber" : "300",
"currentTimestamp" : "2",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"code" : "0x434342444041454545045bf2f23a55",
"data" : "0x",
"gas" : "10000",
"gasPrice" : "100000000000000",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"code" : "0x434342444041454545045bf2f23a55",
"nonce" : "0",
"storage" : {
}
}
}
}
}

View File

@ -249,5 +249,63 @@
} }
} }
} }
},
"sha3_bigOffset" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"code" : "0x60027e0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
"data" : "0x",
"gas" : "1099511627776",
"gasPrice" : "1",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "115792089237316195423570985008687907853269984665640564039457584007913129639935"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"code" : "0x60027e0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
"nonce" : "0",
"storage" : {
}
}
}
},
"sha3_bigSize" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : "1",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"code" : "0x7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
"data" : "0x",
"gas" : "1099511627776",
"gasPrice" : "1",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "115792089237316195423570985008687907853269984665640564039457584007913129639935"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"code" : "0x7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
"nonce" : "0",
"storage" : {
}
}
}
} }
} }

View File

@ -0,0 +1,5 @@
# Automatic deployment of the random test generator
Testing is done in a Vagrant virtual machine
install vagrant, virtualbox, ansible, then do `vagrant up`. It should provison a basic machine. `vagrant ssh` to verify the machine is working as expected. `vagrant terminate` to reset machine to clean state.

78
tests/files/ansible/Vagrantfile vendored Normal file
View File

@ -0,0 +1,78 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION ||= "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# All Vagrant configuration is done here. The most common configuration
# options are documented and commented below. For a complete reference,
# please see the online documentation at vagrantup.com.
# Every Vagrant virtual environment requires a box to build off of.
config.vm.box = "ubuntu/trusty64"
config.vm.define "random-test"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# config.vm.network "forwarded_port", guest: 80, host: 8080
# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# If true, then any SSH connections made will enable agent forwarding.
# Default value: false
# config.ssh.forward_agent = true
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
# # Don't boot with headless mode
# vb.gui = true
#
# # Use VBoxManage to customize the VM. For example to change memory:
# vb.customize ["modifyvm", :id, "--memory", "1024"]
# end
config.vm.provider "virtualbox" do |vb|
# Ubuntu / Virtualbox workaround.
# see http://askubuntu.com/questions/238040/how-do-i-fix-name-service-for-vagrant-client
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
# cpp client needs a lot of RAM to build
vb.customize ["modifyvm", :id, "--memory", "2048"]
end
#
# View the documentation for the provider you're using for more
# information on available options.
# Ansible
config.vm.provision "ansible" do |ansible|
ansible.playbook = "site.yml"
end
end

View File

@ -0,0 +1,8 @@
---
- name: Provision the operation system for tests
# testing
hosts: all
# live
# hosts: TDB
roles:
- common

View File

@ -0,0 +1,28 @@
---
- name: install docker
sudo: true
# install script from https://docs.docker.com/installation/ubuntulinux/
shell: curl -sSL https://get.docker.com/ubuntu/ | sudo sh
- name: install package dependencies
sudo: true
apt: name={{ item }}
with_items:
- python-pip
- htop
- name: install python dependencies
sudo: true
pip: name=docker-py
- name: enable docker for standard user
sudo: true
# todo: how to logout after this command, otherwise won't be effective in this play
user: name=vagrant groups=docker append=yes
- name: checkout test repo
git:
repo: https://github.com/sveneh/tests.git
version: develop
dest: git

View File

@ -0,0 +1,18 @@
---
- name: update C++ client
sudo: true
docker_image:
path: git/ansible/test-files/docker-cpp
name: cpp
state: build
- name: update Go client
sudo: true
docker_image:
path: git/ansible/test-files/docker-go
name: go
state: build
- name: Run infinite tests (press ^C to stop)
sudo: true
shell: git/ansible/test-files/testrunner.sh

View File

@ -0,0 +1,3 @@
---
- include: host-config.yml
- include: testrunner-config.yml

View File

@ -0,0 +1,32 @@
# adjusted from https://github.com/ethereum/cpp-ethereum/blob/develop/docker/Dockerfile
FROM ubuntu:14.04
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update
RUN apt-get upgrade -y
# Ethereum dependencies
RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcurl4-openssl-dev wget
RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
# NCurses based GUI (not optional though for a succesful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 )
RUN apt-get install -qy libncurses5-dev
# Qt-based GUI
# RUN apt-get install -qy qtbase5-dev qt5-default qtdeclarative5-dev libqt5webkit5-dev
# Ethereum PPA
RUN apt-get install -qy software-properties-common
RUN add-apt-repository ppa:ethereum/ethereum
RUN apt-get update
RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev
# Build Ethereum (HEADLESS)
RUN git clone --depth=1 --branch develop https://github.com/ethereum/cpp-ethereum
RUN mkdir -p cpp-ethereum/build
RUN cd cpp-ethereum/build && cmake .. -DCMAKE_BUILD_TYPE=Release -DHEADLESS=1 && make -j $(cat /proc/cpuinfo | grep processor | wc -l) && make install
RUN ldconfig
ENTRYPOINT ["/cpp-ethereum/build/test/createRandomTest"]

View File

@ -0,0 +1,46 @@
# Adjusted from https://github.com/ethereum/go-ethereum/blob/develop/Dockerfile
FROM ubuntu:14.04
## Environment setup
ENV HOME /root
ENV GOPATH /root/go
ENV PATH /go/bin:/root/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
RUN mkdir -p /root/go
ENV DEBIAN_FRONTEND noninteractive
## Install base dependencies
RUN apt-get update && apt-get upgrade -y
RUN apt-get install -y git mercurial build-essential software-properties-common pkg-config libgmp3-dev libreadline6-dev libpcre3-dev libpcre++-dev
## Build and install Go
RUN hg clone -u release https://code.google.com/p/go
RUN cd go && hg update go1.4
RUN cd go/src && ./make.bash && go version
## Install GUI dependencies
RUN add-apt-repository ppa:ubuntu-sdk-team/ppa -y
RUN apt-get update -y
RUN apt-get install -y qtbase5-private-dev qtdeclarative5-private-dev libqt5opengl5-dev
## Fetch and install serpent-go
RUN go get -v -d github.com/ethereum/serpent-go
WORKDIR $GOPATH/src/github.com/ethereum/serpent-go
# RUN git checkout master
RUN git submodule update --init
RUN go install -v
# Fetch and install go-ethereum
RUN go get -v -d github.com/ethereum/go-ethereum/...
WORKDIR $GOPATH/src/github.com/ethereum/go-ethereum
RUN git checkout develop
RUN git pull
RUN ETH_DEPS=$(go list -f '{{.Imports}} {{.TestImports}} {{.XTestImports}}' github.com/ethereum/go-ethereum/... | sed -e 's/\[//g' | sed -e 's/\]//g' | sed -e 's/C //g'); if [ "$ETH_DEPS" ]; then go get $ETH_DEPS; fi
RUN go install -v ./cmd/ethtest
# Run JSON RPC
ENTRYPOINT ["ethtest"]
EXPOSE 8080

View File

@ -0,0 +1,56 @@
#!/bin/bash
# create random virtual machine test
#cd ~/software/Ethereum/pyethereum (python has local dependencies so only works from within the directory)
while [ 1 ]
do
TEST="$(docker run --rm cpp)"
# echo "$TEST"
# test pyethereum
#OUTPUT_PYTHON="$(python ./tests/test_vm.py "$TEST")"
#RESULT_PYTHON=$?
# test go
OUTPUT_GO="$(docker run --rm go "$TEST")"
RESULT_GO=$?
# test cpp-jit
#OUTPUT_CPPJIT="$(~/software/Ethereum/cpp-ethereum/build/test/checkRandomTest "$TEST")"
#RESULT_CPPJIT=$?
# go fails
if [ "$RESULT_GO" -ne 0 ]; then
echo Failed:
echo Output_GO:
echo $OUTPUT_GO
echo Test:
echo "$TEST"
echo "$TEST" > FailedTest.json
mv FailedTest.json $(date -d "today" +"%Y%m%d%H%M")GO.json # replace with scp to central server
fi
# python fails
#if [ "$RESULT_PYTHON" -ne 0 ]; then
# echo Failed:
# echo Output_PYTHON:
# echo $OUTPUT_PYTHON
# echo Test:
# echo "$TEST"
# echo "$TEST" > FailedTest.json
# mv FailedTest.json $(date -d "today" +"%Y%m%d%H%M")PYTHON.json
#fi
# cppjit fails
#if [ "$RESULT_CPPJIT" -ne 0 ]; then
# echo Failed:
# echo Output_CPPJIT:
# echo $OUTPUT_CPPJIT
# echo Test:
# echo "$TEST"
# echo "$TEST" > FailedTest.json
# mv FailedTest.json $(date -d "today" +"%Y%m%d%H%M")CPPJIT.json
#fi
done

View File

@ -0,0 +1,12 @@
---
- name: preparing and running tests
# testing
hosts: all
# live
# hosts: TBD
# TODO use the right user for configuring, until credentials set, stay with default vagrant user
# remote_user: ubuntu
roles:
- testrunner

View File

@ -1,36 +1,6 @@
module.exports = { module.exports = {
blockgenesis: require('./BasicTests/blockgenesistest'), basicTests: require('require-all')(__dirname + '/BasicTests/'),
genesishashes: require('./BasicTests/genesishashestest'), trieTests: require('require-all')(__dirname + '/TrieTests/'),
hexencode: require('./BasicTests/hexencodetest'), stateTests: require('require-all')(__dirname + '/StateTests/'),
keyaddrtests: require('./BasicTests/keyaddrtest'), vmTests: require('require-all')(__dirname + '/VMTests')
rlptest: require('./BasicTests/rlptest'),
trieTests: {
trietest: require('./TrieTests/trietest'),
trietestnextprev: require('./TrieTests/trietestnextprev'),
trieanyorder: require('./TrieTests/trieanyorder')
},
txtest: require('./BasicTests/txtest'),
StateTests: {
stExample: require('./StateTests/stExample.json'),
stInitCodeTest: require('./StateTests/stInitCodeTest.json'),
stLogTests: require('./StateTests/stLogTests.json'),
stPreCompiledContracts: require('./StateTests/stPreCompiledContracts'),
stRecursiveCreate: require('./StateTests/stRecursiveCreate'),
stRefundTest: require('./StateTests/stRefundTest'),
stSpecial: require('./StateTests/stSpecialTest'),
stSystemOperationsTest: require('./StateTests/stSystemOperationsTest'),
stTransactionTest: require('./StateTests/stTransactionTest')
},
VMTests: {
vmRandom: require('./VMTests/RandomTests/randomTest'),
vmArithmeticTest: require('./VMTests/vmArithmeticTest'),
vmBitwiseLogicOperationTest: require('./VMTests/vmBitwiseLogicOperationTest'),
vmBlockInfoTest: require('./VMTests/vmBlockInfoTest'),
vmEnvironmentalInfoTest: require('./VMTests/vmEnvironmentalInfoTest'),
vmIOandFlowOperationsTest: require('./VMTests/vmIOandFlowOperationsTest'),
vmLogTest: require('./VMTests/vmLogTest'),
vmPushDupSwapTest: require('./VMTests/vmPushDupSwapTest'),
vmSha3Test: require('./VMTests/vmSha3Test'),
vmtests: require('./VMTests/vmtests')
}
}; };

View File

@ -19,5 +19,8 @@
"bugs": { "bugs": {
"url": "https://github.com/ethereum/tests/issues" "url": "https://github.com/ethereum/tests/issues"
}, },
"homepage": "https://github.com/ethereum/tests" "homepage": "https://github.com/ethereum/tests",
"dependencies": {
"require-all": "^1.0.0"
}
} }

View File

@ -7,10 +7,10 @@ import (
"log" "log"
"os" "os"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/whisper" "github.com/ethereum/go-ethereum/whisper"
"github.com/obscuren/secp256k1-go"
) )
func main() { func main() {

View File

@ -81,7 +81,7 @@ func (self *peer) broadcast(envelopes []*Envelope) error {
if err := self.ws.WriteMsg(msg); err != nil { if err := self.ws.WriteMsg(msg); err != nil {
return err return err
} }
self.peer.Infoln("broadcasted", i, "message(s)") self.peer.DebugDetailln("broadcasted", i, "message(s)")
} }
return nil return nil